computed

作者: 狐尼克朱迪 | 来源:发表于2017-03-01 15:02 被阅读0次

    我们通过下面的例子来看下 computed 属性的实现机制。为了简单起见,我们创建一个没有挂载节点的Vue实例。

    var example = new Vue({
          data: {
            a: 1
          },
          computed: {
            b: function () {
              return this.a + 1
            }
          }
        })
    
        example.a++
        console.log(example.b) // -> 3
        example.a = 5
        console.log(example.b) // -> 6
    

    data属性

    computed属性中的方法和data属性直接相关,data对象的字段都会经过如下方法实现响应式:

    function defineReactive (obj, key, val) {
      var dep = new Dep() // dep对象负责维护订阅列表(对数据而言,就是Watcher对象)
    
      // cater for pre-defined getter/setters
      var getter, setter
      if (config.convertAllProperties) {
        var property = Object.getOwnPropertyDescriptor(obj, key)
        if (property && property.configurable === false) {
          return
        }
        getter = property && property.get
        setter = property && property.set
      }
    
      var childOb = observe(val)
      Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function reactiveGetter () {
          var value = getter ? getter.call(obj) : val
          if (Dep.target) {  // Dep.target是个Watcher对象实例
            dep.depend()  // 把Dep.target这个Watcher对象加入到dep的subs列表中
            if (childOb) {
              childOb.dep.depend()
            }
            if (isArray(value)) {
              for (var e, i = 0, l = value.length; i < l; i++) {
                e = value[i]
                e && e.__ob__ && e.__ob__.dep.depend()
              }
            }
          }
          return value
        },
        set: function reactiveSetter (newVal) {
          var value = getter ? getter.call(obj) : val
          if (newVal === value) {
            return
          }
          if (setter) {
            setter.call(obj, newVal)
          } else {
            val = newVal
          }
          childOb = observe(newVal)
          // 此处会调用依赖列表的watcher进行数据视图的同步! 
          // watcher会调用directive的更新方法
          dep.notify()
        }
      })
    }
    

    computed属性

    初始化时,computed属性的主要方法如下:

    Vue.prototype._initComputed = function () {
        var computed = this.$options.computed
        if (computed) {
          for (var key in computed) {
            var userDef = computed[key]
            var def = {
              enumerable: true,
              configurable: true
            }
            if (typeof userDef === 'function') {
              def.get = makeComputedGetter(userDef, this)
              def.set = noop
            } else {
              def.get = userDef.get
                ? userDef.cache !== false
                  ? makeComputedGetter(userDef.get, this)
                  : bind(userDef.get, this)
                : noop
              def.set = userDef.set
                ? bind(userDef.set, this)
                : noop
            }
            Object.defineProperty(this, key, def)
          }
        }
      }
    
      function makeComputedGetter (getter, owner) {
        var watcher = new Watcher(owner, getter, null, {
          lazy: true
        })
        return function computedGetter () {
          if (watcher.dirty) {
            watcher.evaluate()
          }
          if (Dep.target) {
            watcher.depend()
          }
          return watcher.value
        }
      }
    

    关联

    第一次获取computed属性中的字段的值时,会因为watcher的lazy为true,执行一次evaluate方法,而且会把watcher加入到data字段的订阅者列表中。

    DOM节点中有和computed属性相关的字段,会在调用get方法时,通过computed中的getter方法完字段取值、依赖搜集。

    如果对computed中的字段直接设值,并不能引起View的变化。

    相关文章

      网友评论

          本文标题:computed

          本文链接:https://www.haomeiwen.com/subject/zhkupttx.html