vue2.0中的计算属性

计算属性是一个很邪门的东西,只要在它的函数里引用了data中的某个属性,当这个属性发生变化的时候,函数仿佛可以嗅探到这个变化,并自动重新执行。

View Code

上代码会源源不断的打印出a的值。如果希望b依赖data中的x而变化,只需要保证b函数中有this.x即可。如果函数中没有出现data中的属性,那么无论data中的属性怎么变,b对应的函数一次也不会执行。

 

Vue是怎么知道计算属性在函数中引用了哪个data属性?这个函数又是怎么知道data属性变了,而且只关心它内部引用的那个属性,别的都不管?官方文档是这么说的:

我们简单模拟实现一个计算属性:a变化时,b自动跟着变化。

var obj = {
  a:0,
  b:function(){
    var a = this.a;
    return a + 1;
  }
}

由于涉及到Vue的双向绑定的原理,如果你对此不熟,最好先看看《Vue.js双向绑定的实现原理》

程序执行过程:

1、首先b属性会被处理为存取器属性,访问b就会触发其get函数;

2、处理计算属性a时,会执行a的函数,从而会执行this.b,于是触发b的get函数;

3、b的get函数会添加b属性的依赖项,而刚才在处理计算属性过程中,a已经作为依赖项被传给了一个全局变量,b的get函数会检测到这个全局变量,并将其添加到自身的订阅者列表中;

4、对b赋予新的值时,会触发其set函数,set函数中会遍历执行订阅者,a的值就是在这个时候更新的。

再看代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Two-way-data-binding</title>
  </head>
  <body>
    <script>
      var Dep = null;

      function defineReactive(obj, key, val) {
        var deps = [];
        Object.defineProperty(obj, key, {
          get: function () {
            if (Dep) {
              deps.push(Dep);
            }
            return val;
          },
          set: function (newval) {
            val = newval;
            deps.forEach(func => func());
          }
        })
      }

      function defineComputed(obj, key, func) {
        func = func.bind(obj);
        var value;
        Dep = function () {
          value = func();
        };
        value = func();
        Dep = null;
        Object.defineProperty(obj, key, {
          get: function () {
            return value;
          }
        })
      }

      var obj = {};
      defineReactive(obj, 'a', 0);
      defineComputed(obj, 'b', function () {
        var a = this.a;
        return a + 1;
      })
    </script>
  </body>
</html>
View Code

通过对存取器属性、闭包和观察者模式的综合运用,Vue巧妙的实现了计算属性。可以看出,Vue响应式系统的核心理念是“依赖”,DOM节点之所以随数据而变化,是因为节点依赖于数据,计算属性之所以随数据而变化,是因为计算属性依赖于数据,做好响应式的关键就在于处理好依赖关系。

 

参考文章:https://skyronic.com/blog/vuejs-internals-computed-properties

 

posted @ 2017-12-27 07:06  Z皓  阅读(985)  评论(0编辑  收藏  举报