原文:vue 是如何对数组方法进行变异的? - 每天一个JavaScript小知识@Js中文网 · 码农进阶题库

原文地址:https://www.javascriptc.com/interview-tips/zh_cn/vue/vue-array-variation/

vue 是如何对数组方法进行变异的?例如 push、pop、splice 等方法

解题1:

  1. 为什么要对数组进行单独处理 在Vue现有阶段中,对响应式处理利用的是Object.defineProperty对数据进行拦截,而这个方法并不能监听到数组内部变化,数组长度变化,数组的截取变化等,所以我们需要对这些操作进行hack,让vue能监听到其中的变化。

2.怎么对数组进行处理

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':
          // [].push(1),[].unshift(1)
          // arg = [1]
          inserted = args;
          break
        case 'splice':
          // [1,2,3].splice(0,1,1)
          // 第三个参数为插入的值
          inserted = args.slice(2);
          break
      }
      if (inserted) { ob.observeArray(inserted); }
      // 监听变化,如果不是插入操作直接循环响应
      // 如果是去除数组参数方法,触发一次notify将会重新计算
      // 如果仅仅是数字数据,任何操作只需要再次执行一次notify则可以
      // 但是如果新增的是一个对象类型,就需要重新监听
      // 为什么用角标和length属性不能监听的原因是因为无法触发obj的get方法,所以没法动态监听
      // notify change
      ob.dep.notify();
      return result
    });
  });

正如该题所问,vue对push,pop,splice等方法进行了hack,hack方式很简单,如果加入新对象,对新对象进行响应式化,至于如何响应式化请参考vue源码。 举例来说对于push和unshift会推入一个新的对象到数组里(不管从前还是从后),记录这个加入的对象,并调用Observe方法将加入的对象转换成响应式对象,对于splice方法,如果加入了新对象也是将该对象响应式化。 最后一步是向外抛出数组变化,提醒观察者进行更新。

3.存在问题 对于Object.defineProperty的缺陷导致如果直接改变数组下标是无法hack的,由于此点,vue提供了$set方法,最新的解决方案当然是利用Proxy对象进行监听,但是Proxy的缺陷在于兼容性,可能会为了性能以及便利而放弃兼容性吧,一切都要看尤大的决定了。

4.变异的本质就在这些方法内部加上自定义的逻辑,其实就是想监听这些方法的调用。

Vue中默认的做法就是在数组实例与它的原型之间,插入了一个新的原型对象,这个原型方法实现了这些变异方法,也就拦截了真正数组原型上的方法(因为原型链的机制,找到了就不会继续往上找了)。 变异方法中增加了自定义逻辑,也调用了真正数组原型上的方法,即实现了目的,也不会对正常使用造成影响。

如果浏览器不支持___proto__这个属性,Vue则直接在数组实例上增加这些变异方法。

解题2 ?:

:point_down:~~~~ 欢迎在下方评论补充你的答案,一起来学习~:pushpin:

扩展阅读: