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...

相關文章
相關標籤/搜索