VUE数组响应式

vue 为什么没用Object.defineProperty来实现对数组属性的监听

Object.defineProperty 可以做到对数组的监听,它是支持数组的

例如

let array = [1,2,3,4,5]

array.forEach((c,index) => {
    defineReactive(array, index, c)
})
function defineReactive(obj, key, val) {
    Object.defineProperty(obj, key, {
        enumerable: true, // 属性可枚举
        configurable: true,
        get() {
            return val;
        },
        set(newVal) {
            if (val === newVal) return
            val = newVal
        }
    })
}

我们可以遍历数组,用数组的索引作为 key,来给每一项打上getter/setter。

Object.defineProperty 有这个能力,但是vue 为什么没用它来实现对数组属性的监听

原因:

  1. 如果你知道数组的长度,理论上是可以预先给所有的索引设置 getter/setter 的。但是一来很多场景下你不知道数组的长度
  2. 性能问题,数组可能会很长,综合考虑不对数组属性进行监听

VUE针对数组情况的做法

重写了数组原型链上的七种方法('push','pop','shift','unshift','splice','sort','reverse'),

在内部调用了数组的原始方法,最后通过ob.dep.notify()更新视图

  var arrayProto = Array.prototype;
  var arrayMethods = Object.create(arrayProto);

  var methodsToPatch = [
    'push',
    'pop',
    'shift',
    'unshift',
    'splice',
    'sort',
    'reverse'
  ];

  /**
   * Intercept mutating methods and emit events
   */
  methodsToPatch.forEach(function (method) {
    // cache original method
    var original = arrayProto[method];
    // def给arrayMethods对象添加method属性
    def(arrayMethods, method, function mutator () {
      var args = [], len = arguments.length;
      while ( len-- ) args[ len ] = arguments[ len ];

      var result = original.apply(this, args);
      var ob = this.__ob__;
      var inserted;
      switch (method) {
        case 'push':
        case 'unshift':
          inserted = args;
          break
        case 'splice':
          inserted = args.slice(2);
          break
      }
      if (inserted) { ob.observeArray(inserted); }
      // notify change
      // 更新视图
      ob.dep.notify();
      return result
    });
  });  var arrayProto = Array.prototype;
  var arrayMethods = Object.create(arrayProto);

  var methodsToPatch = [
    'push',
    'pop',
    'shift',
    'unshift',
    'splice',
    'sort',
    'reverse'
  ];

  /**
   * Intercept mutating methods and emit events
   */
  methodsToPatch.forEach(function (method) {
    // cache original method
    var original = arrayProto[method];
    // def给arrayMethods对象添加method属性
    def(arrayMethods, method, function mutator () {
      var args = [], len = arguments.length;
      while ( len-- ) args[ len ] = arguments[ len ];

      var result = original.apply(this, args);
      var ob = this.__ob__;
      var inserted;
      switch (method) {
        case 'push':
        case 'unshift':
          inserted = args;
          break
        case 'splice':
          inserted = args.slice(2);
          break
      }
      if (inserted) { ob.observeArray(inserted); }
      // notify change
      // 更新视图
      ob.dep.notify();
      return result
    });
  });

observeArray 会把数组里面的对象数据变成是可侦测的响应式数据

原文地址:https://www.cnblogs.com/wangxirui/p/15785309.html