vue对数组的处理

217 阅读1分钟

vue利用defineProperty实现了监听器的功能。但当使用push、pop等方法来修改数组对象时,不会触发setter方法,即这时监听不到数组的变化。
vue对push、pop、shift、unshift、splice、sort、reverse这几个原型方法进行了改写。

改写真实数组的__proto__,如

arr.__proto__=arrayMethods;

让arrayMethods的__proto__指向Array.prototype

const arrayProto = Array.prototype;
export const arrayMethods = Object.create(arrayProto);

定义arrayMethods上的一些方法

const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]
methodsToPatch.forEach(function (method) {
  const original = arrayProto[method] 
  def(arrayMethods, method, function mutator (...args) { //在arrayMethods上定义push等方法
    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等基础上增加以下功能
    //监听变化,通知变化
    if (inserted) ob.observeArray(inserted)  
    ob.dep.notify()
    return result
  })
})

这时,一个数组对象的结构如下图。
当我们访问push方法时,访问到的是改写后的方法,会给新插入的元素添加监听器,并通知变化。当访问map等方法时,访问的是arr.proto.proto.map(即arrayMethods.proto.map),也就是原型上的map方法。