vue2.0的数组劫持

2019-12-02  本文已影响0人  Mr无愧于心

Object.defineProperty不支持监听数组变化。所以需要重写数组上面的方法。

vue2.0对数组的方法进行了劫持,重写了能改变数组的方法实现数据的更新

const arrayProto = Array.prototype//原生Array的原型
export const arrayMethods = Object.create(arrayProto);
[
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
].forEach(function (method) {
  const original = arrayProto[method]//缓存元素数组原型
  //这里重写了数组的几个原型方法
  def(arrayMethods, method, function mutator () {
    //这里备份一份参数应该是从性能方面的考虑
    let i = arguments.length
    const args = new Array(i)
    while (i--) {
      args[i] = arguments[i]
    }
    const result = original.apply(this, args)//原始方法求值
    const ob = this.__ob__//这里this.__ob__指向的是数据的Observer
    let inserted
    switch (method) {
      case 'push':
        inserted = args
        break
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
    }
    if (inserted) ob.observeArray(inserted)
    // notify change
    ob.dep.notify()
    return result
  })
})

//定义属性
function def (obj, key, val, enumerable) {
  Object.defineProperty(obj, key, {
    value: val,
    enumerable: !!enumerable,
    writable: true,
    configurable: true
  });
}

上面的代码主要是继承了Array本身的原型方法,然后又做了劫持修改,可以发出通知。
  Vue在observer数据阶段会判断如果是数组的话,则修改数组的原型,这样的话,后面对数组的任何操作都可以在劫持的过程中控制。

// 以上代码 相当于
var bar = [1,2];
bar.__proto__ = arrayMethod;
// 执行
bar.push(3); 就会触发arrayMethods中的代码:ob.dep.notify()就会被触发,就会通知watcher触发template的更新。
上一篇下一篇

猜你喜欢

热点阅读