1. 程式人生 > >Vue原理系列-Vue.js 計算屬性的祕密

Vue原理系列-Vue.js 計算屬性的祕密

計算屬性是一個很邪門的東西,只要在它的函式裡引用了 data 中的某個屬性,當這個屬性發生變化時,函式彷彿可以嗅探到這個變化,並自動重新執行。

      上述程式碼會源源不斷的打印出 b 的值。如果希望 a 依賴 data 中的 x 而變化,只需保證 a 函式中有 this.x 即可。如果函式中沒有出現 data 中的屬性,那麼無論 data 中的屬性怎麼變,a 對應的函式一次也不會執行。

      Vue 怎麼知道計算屬性在函式中引用了哪個 data 屬性?這個函式又是怎麼知道 data 屬性變了,而且只關心它內部引用的那個屬性,別的都不管?

      官方文件對計算屬性的描述是:

      文件的描述讓我的困惑更加困惑,還有這種操作?這特麼是怎麼做到的?

      Google 了一把,看了一篇三哥的博文(見文末),豁然開朗。

      我們簡單模擬實現一個計算屬性:a 變化時,b 自動跟著變化。

      由於涉及 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 的值就是在這個時候更新的

      再看程式碼:

(注:圖中數字僅作思路引導,並非與前文過程描述對應)

      測試一下,完美打印出 1, 2, 3, 4

      console.log(obj.b)

      obj.a += 1;

      console.log(obj.b);

      obj.a += 1;

      console.log(obj.b);

      obj.a += 1;

      console.log(obj.b);

      通過對存取器屬性、閉包和觀察者模式的綜合運用,Vue 巧妙的實現了計算屬性。現在再看官方文件描述,是不是更通透了呢。

      可以看出,Vue 響應式系統的核心理念是“依賴”,DOM 節點之所以隨資料而變化,是因為節點依賴於資料,計算屬性之所以隨資料而變化,是因為計算屬性依賴於資料。做好響應式的關鍵就在於處理好依賴關係。