Vue2.x源码学习笔记(五)——响应式原理之数组的侦测

209 阅读1分钟

Observer

export class Observer {
  value: any;
  dep: Dep;
  vmCount: number; // number of vms that have this object as root $data

  constructor (value: any) {
    this.value = value
    this.dep = new Dep()
    this.vmCount = 0
    def(value, '__ob__', this)
    if (Array.isArray(value)) {
      if (hasProto) {
        protoAugment(value, arrayMethods)
      } else {
        copyAugment(value, arrayMethods, arrayKeys)
      }
      this.observeArray(value)
    } else {
    
    }
  }
  observeArray (items: Array<any>) {
    for (let i = 0, l = items.length; i < l; i++) {
      observe(items[i])
    }
  }
}

observer类中如果是数组,则会先劫持数组的原型,对数组原型进行改造。然后再通过observeArray方法去循环调用observe方法。使数组中的每一项都被侦测。

数组原型劫持

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) {
    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
    }
    if (inserted) ob.observeArray(inserted)
    ob.dep.notify()
    return result
  })
})

通过Object.create继承数组的原型得到arrayMethods,然后对数组的7个方法进行重写并添加到arrayMethods的原型上。

先保存一份原来的数组方法,并获取原来数组方法的返回值。然后重写方法。对于push,unshift,splice有插入值操作的方法,会对插入的值继续通过observeArray侦测。然后获取数组的响应式标记__ob__,即observer类。因为observer类也有dep实例,所以通过this.ob.dep.notify()去派发更新。最后返回原先数组方法的返回值。

protoAugment和copyAugment

protoAugment中将数组的__proto__指向新的原型对象。 如果不兼容的情况下可以使用copyAugment,将每一项手动添加到数组新原型。

dependArray

function dependArray (value: Array<any>) {
  for (let e, i = 0, l = value.length; i < l; i++) {
    e = value[i]
    e && e.__ob__ && e.__ob__.dep.depend()
    if (Array.isArray(e)) {
      dependArray(e)
    }
  }
}

在defineReactive中对于value是数组的单独处理。循环数组,对于数组的每一项进行收集依赖。