Vue源码实现--依赖收集(2)

关于上一篇的几点疑问其实在看源码的过程中已经看明白了,但是回过头来发现又容易忘了,这也是我决定写几篇文章记录一下的原因。

数组的依赖收集:

 我们都知道vue中,直接改变一个数组(比如arr[1] = 2)是不会触发页面的更新的,必须调用数组的方法:arr.splice(1,1,2)才可以。
 简单说一下vue的实现:其实我们调用的splice方法并不是数组原生的方法,当observer(data)时,如果data是一个数组,那么此时就用事先定义的七个方法(push,pop,shift,unshift,sort,reverse,splice)替换掉原来数组上的方法。

  /*Observer Array*/
  var initArrayMethod = function (arr) {
    var arrayProto = Array.prototype
    // 复制原生数组原型上的方法,并替换掉其中的7个
    var arrayMethods = Object.create(arrayProto)
    ;['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function(method) {
      var origin = arrayMethods[method]
      arrayMethods[method] = function () {
        // 保存原生数组调用的结果
        var result = origin.apply(this, arguments)
        // 这里就是调用被观测的属性上的dep(__ob__)
        this.__ob__.dep.notify())
        return result
      }
    })
    arr.__proto__ = arrayMethods
  }

 什么时候收集的依赖呢,代码戳这里:childOb
 上面的代码中,this.ob.dep.notify()就是为什么需要在被观测的对象中也维护一个dep实例了(ob),对象上的ob主要用在这两个地方:一个就是调用数组方法之后触发订阅者回调,另一个就是vue中调用set,del方法时触发订阅者。
 对比源码可以发现,比上面的的代码要多一些,那么有什么不同呢?其实主要是这一行代码:

if (inserted) ob.observeArray(inserted)

ob.observeArray()是对数组中数据进行observe,主要是对数组嵌套对象,数组嵌套数组这种情况进行依赖收集,在这里就是对push,unshift,splice这三个有插入新的数据的方法对新插入的数据observe。
包括在Observer类中,为了使代码简便,在这里我暂时都没对数组嵌套对象的情况进行处理

深观测一个对象:

 watch方法的options中,有个deep参数,设置为true的时候,就可以深观测一个对象,其实原理非常简单,就是在依赖收集的时候遍历对象的每一个属性,触发每一个属性的getter,那么每个属性都会被依赖收集
 经过上面的处理,现在我们的vue依赖收集多了这些功能:

    var app = new Vue({
      data: function () {
        return {
          a: 1,
          b: {
            c: 2
          },
          arr: [1,2,3]
        }
      }
    })
    app.$watch('a', function () {
      console.log('a is change')
    })
    app.$watch('arr', function () {
      console.log('arr is change')
    })
    app.$watch('b', function () {
      console.log('b is change')
    }, {deep: true})
    var test = app.arr.splice(0,1,11)
    app.b.c = 3

返回结果为:

arr is change
b is change

附上本文的完整代码:附件

你可能感兴趣的:(Vue源码实现--依赖收集(2))