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

watch一个Computed属性:

 其实了解完前面的依赖收集原理之后,watch一个computed属性和data属性并没有什么区别,就是代理computed属性到vm实例上去,那么在依赖收集的时候computed中包含的属性也会被收集到,代码如下:

  // 初始化computed
  function initComputed (vm) {
    var computed = vm._computed = vm.$options.computed
    var keys = Object.keys(computed)
    var i = keys.length
    while (i--) {
      proxyComputed(vm, keys[i])
    }
  }
  // 代理computed属性到vm实例上
  function proxyComputed (vm, key) {
    Object.defineProperty(vm, key, {
      configurable: true,
      enumerable: true,
      get: function () {
        return vm._computed[key].call(vm)
      }
    })
  }

执行代码:

    var app = new Vue({
      data: function () {
        return {
          a: 1,
          b: {
            c: 2
          },
          arr: [1,2,3]
        }
      },
      computed: {
        computed1: function () {
          return this.a + this.b.c
        }
      }
    })
    app.$watch('a', function () {
      console.log('a is change')
    })
    app.$watch('computed1', function () {
      console.log('computed1 is change')
    })
    app.a = 2

输出结果:

a is change
computed1 is change

完美!但是一看vue的源码,实现起来似乎复杂好多,那么vue为什么要那样做呢,看来事情并不简单(托了下眼镜)。
其实vue的源码中,Watcher的options中有一个lazy的参数,这个参数主要就是用在computed中的。(相关源码)
lazy watcher主要就是实现了vue中computed的缓存,我们都知道,computed计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。这就是靠lazy watcher实现的。
我就试着用自己的语言说说vue中的lazy watcher的思路吧。
1.为每个定义的computed属性创建一个内部的监视器(lazy Watcher实例),保存在vm._computedWatchers中,lazy Watcher的dirty属性为默认true,数据为脏,因为定义时不去计算watcher的值,首次访问时才会去计算并收集此watcher到computed相关属性的dep中。
2.代理computed属性到vm实例,在代理属性的getter中,若数据为脏,则调用lazyWatcher的evaluate计算最新的数据,并设置dirty为false。若数据不为脏,则直接返回lazyWatcher的value。
3.computed相关的属性更新时候,会触发执行lazyWatcher的update方法;若是lazyWatcher,则在update方法中只会把watcher的dirty设置为true,等下次引用该watcher的时候就会按上述步骤重新计算值

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