vue.js 计算属性内幕

vue计算属性特别好用,可是它是如何作到的这一点的呢?vue

咱们首先从一个案例开始。它有一个input能够输入货币值,另一个span会把货币加上一¥符号。当货币值变化时,span会跟着变化:git

<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
  <input v-model="money"></input>
  <span>{{RMB}}</span>
</div>
<script>
  new Vue({
    el:'#app',
    data:{
      money:1.10
    },
    computed:{
      RMB:function(){
        return '¥'+this.money
      }
    }
  })
</script>

这里的RMB属性就是一个计算属性,依赖于this.money,伴随后者的变化而变化。bootstrap

然而,这是如何作到的?难道vuejs分析了rmb函数内的表达式吗。要知道这一点,咱们得了解响应式属性的概念和技术。经过DefineProperty,能够建立一个看起来是普通数据,可是背后还有getter/setter函数的属性,像是这样:app

var bank = {moneyNormal:1};

  Object.defineProperty (bank, 'money', {
    get: function () {
      console.log ("Getting money");
      return 1;
    }
  });
  console.log ("money:", bank.money,bank.moneyNormal);

尽管使用起来bank.money和bank.moneyNormal差很少,实际上每次访问money会首先通过getter函数,这样就能够在此函数内作些本身想要作的事儿。vue就是会把全部在data返回的属性作一次DefineProperty处理,把它变成响应式的属性,所以每次访问此类属性,vue均可以知道的。这一点对于计算属性相当重要!函数

再进一步,就是当RMB计算属性被调用执行时,必然会调用到this.money,this.money会引起它本身的getter函数。所以只要在RMB属性调用this.money以前作些手脚,让this.money的getter知道此调用是从RMB getter来的便可记录以来,将来改变this.money,就能够通知依赖,由此引起连锁的更新反应。代码:this

var Dep = {
  target: null 
}
function defineVUEProperty (obj, key, val) {
  var deps = [];
  Object.defineProperty (obj, key, {
    get: function () {
      // 处理计算依赖
      if (Dep.target && deps.indexOf (Dep.target) == -1) {
        deps.push (Dep.target);
      }
      return val;
    },
    set: function (newValue) {
      val = newValue;
      // 处理计算依赖      
      for (var i = 0; i < deps.length; i ++) {
        deps[i]();
      }
    }
  })
}
function defineVUEComputed (obj, key, computeFunc) {
  var onDependencyUpdated = function () {
    var value = computeFunc ();
    console.log('dependence value:'+value)
  };
  
  Object.defineProperty (obj, key, {
    get: function () {
      // 处理计算依赖
      Dep.target = onDependencyUpdated;
      var value = computeFunc ();
      // 处理计算依赖
      Dep.target = null;
      return value;
    }
  })
}
//demo code
var bank = {};
defineVUEProperty (bank, 'money', 1);
defineVUEComputed (bank, 'RMB', function () {
  return '$'+bank.money
});
console.log (bank.money,bank.RMB)
bank.money = 22;

咱们会发现,当执行完代码bank.money = 22;,确实会激发RMB的重算,由于代码打印了:spa

dependence value:¥42

作出手脚的代码已经被标注出来。要点是code

  1. 首先由一个全局变量Dep,它是一个单实例对象,成员为target。orm

  2. 当执行计算属性的getter时,它设置一个回调函数到Dep.target,而后调用被依赖的属性的getter,在此getter内检查Dep.target,若是有值而且没有加入当前属性的依赖列表就把它加进来。这样就把依赖此属性的计算属性指定的回调加入了依赖列表内。对象

  3. 修改属性(调用属性的setter)时,对应的setter函数调用全部前一步加入的依赖列表内的回调,等因而把控制权转移给了对应的计算属性

改编于:Vue.js Internals: How computed properties work | Anirudh Sanjeev

做者:刘传君

建立过产品,创过业。好读书,求甚解。
能够经过 1000copy#gmail.com 联系到我

出品

bootstrap小书 https://www.gitbook.com/book/...
http小书 http://www.ituring.com.cn/boo...
Git小书 http://www.ituring.com.cn/boo...

相关文章
相关标签/搜索