vue中如何监测数组的变化

您所在的位置:网站首页 vue是如何检测数组变化的 vue中如何监测数组的变化

vue中如何监测数组的变化

2023-12-31 17:28| 来源: 网络整理| 查看: 265

一、数组监听与对象监听的不同

对象的监听是直接递归使用Object.defineProperty重新定义数组的每个属性,而数据是改写数组的7个数组方法:push,pop,shift,unshift,sort,splice,reverse

二、实现原理

vue在数据初始化时调用initData方法,然后通过new Observer对数据进行监测,然后对数据进行判断,如果是数组并且支持原型链就会执行protoAugment让目标原型链指向arrayMethods,arrayMethods用来改写数组的原型方法。内部会采用函数劫持的方式,当用户调用这些方法(push,pop,shift,unshift,sort,splice,reverse)之后,还会调用原数组的方法进行更新数组。拿到原数组的方法,然后重新定义这些方法。

        用户调方法时走的就是这个重写的mutator函数,这个函数还是会调用数组原有的方法,重写的mutator函数中会调用原生的方法,对新增数组的方法push,unshift,splice可以帮我们更新数组中的新增一项,对插入的数据使用observeArray再次进行监测,最后通过dep.notify通知视图更新。

源码:

1.在observer方法中

if (Array.isArray(value)) { // 如果是数组 if (hasProto) { // 判断是否支持原型链 protoAugment(value, arrayMethods) // arrayMethods就是改写数组的原型方法 } else { copyAugment(value, arrayMethods, arrayKeys) // 如果没有原型链会走def方法添加__ob__属性 } this.observeArray(value) // 深度监测数组中的每一个元素,遍历一遍数组,调用observe方法进行监测 } else { this.walk(value) }

2.protoAugment

function protoAugment (target, src: Object) { target.__proto__ = src // 让目标的原型链指向src }

3.arrayMethods

const arrayProto = Array.prototype export const arrayMethods = Object.create(arrayProto) const methodsToPatch = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ] // 内部会采用函数劫持的方式,当用户调用这些方法之后,还会调用原数组的方法进行更新数组 methodsToPatch.forEach(function (method) { const original = arrayProto[method] // 将原方法拿到 def(arrayMethods, method, function mutator (...args) { // 然后重新定义这些方法,用户调方法时走的就是这个mutator函数,这个函数还是会调用数组原有的方法 const result = original.apply(this, args) // 原生的方法 const ob = this.__ob__ let inserted switch (method) { case 'push': case 'unshift': inserted = args break case 'splice': inserted = args.slice(2) break // 新增数组的方法push,unshift,splice可以帮我们更新数组中的新增一项 } if (inserted) ob.observeArray(inserted) // 对插入的数据再次进行监测,新增的数据也可能是对象类型 // observeArray是将数组遍历一遍 ob.dep.notify() // 通知视图更新 return result }) })

4.observeArray

observeArray (items: Array) { // 遍历数组,进行监测 for (let i = 0, l = items.length; i < l; i++) { observe(items[i]) // 必须是对象类型才能被监测,如果不是对象在oberve中会被return // 如果数据已经是观察过的就不会在进行观测,会直接返回,避免进行重复监听 } }

5.def方法其实就是Object.defineProperty

export function def (obj: Object, key: string, val: any, enumerable?: boolean) { Object.defineProperty(obj, key, { value: val, enumerable: !!enumerable, writable: true, configurable: true }) }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3