Vue源码解析之数据响应系统的使用(12)

首先缓存了数组原本的变异方法

const original = arrayProto[method]

然后用def在arrayMethods对象上定义了与变异方法同名的函数。函数内首先调用了original原来的函数获取结果

const result = original.apply(this, args)

并在函数末尾返回result。保证了拦截函数的功能与原来方法的功能是一致的。

const ob = this.__ob__
...
ob.dep.notify()

这两句代码就是触发依赖。当变异方法被调用时,数组本身就被改变了,所以要触发依赖。

再看其余的代码:

let inserted
switch (method) {
 case 'push':
 case 'unshift':
  inserted = args
  break
 case 'splice':
  inserted = args.slice(2)
  break
}
if (inserted) ob.observeArray(inserted)

这段代码的作用就是收集新添加的元素,将其变成响应式数据。

push和unshift方法的参数就是要添加的元素,所以inserted = args。splice方法从第三个参数到最后一个参数都是要添加的新元素,所以inserted = args.slice(2)。最后,如果存在新添加的元素,调用observeArray函数对其进行观测。

以上是支持__proto__属性的时候,那不支持的时候呢?调用copyAugment方法,并传递了三个参数。前两个跟protoAugment方法的参数一样,一个是数组实例本身,一个是arrayMethods代理原型,还有一个是arrayKeys,

const arrayKeys = Object.getOwnPropertyNames(arrayMethods)

它的值就是定义在arrayMethods对象上的所有的键,也就是所要拦截的变异方法的名称。函数定义如下:

function copyAugment (target: Object, src: Object, keys: Array<string>) {
 for (let i = 0, l = keys.length; i < l; i++) {
 const key = keys[i]
 def(target, key, src[key]) 
 }
}

这个方法的作用就是在数组实例上定义与变异方法同名的函数,从而实现拦截。

if else代码之后,调用了observeArray方法this.observeArray(value), 并将数组实例作为参数。

observeArray方法的定义如下:

/**
* Observe a list of Array items.
*/
observeArray (items: Array<any>) {
 for (let i = 0, l = items.length; i < l; i++) {
  observe(items[i])
 }
}

循环遍历数组实例,并对数组的每一项再进行观测。这是因为如果数组元素是数组或纯对象的话不进行这一步数组元素就不是响应式的,这是为了实现深度观测。比如:

const vm = new Vue({
 data: {
  a: [[1,2]]
 }
})
vm.a.push(1); // 能够触发响应
vm.a[1].push(1); // 不能触发响应

      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/19.html