計算屬性是一個很邪門的東西,只要在它的函數裏引用了 data 中的某個屬性,當這個屬性發生變化時,函數彷彿能夠嗅探到這個變化,並自動從新執行。html
上述代碼會源源不斷的打印出 b 的值。若是但願 a 依賴 data 中的 x 而變化,只需保證 a 函數中有 this.x 便可。若是函數中沒有出現 data 中的屬性,那麼不管 data 中的屬性怎麼變,a 對應的函數一次也不會執行。vue
Vue 怎麼知道計算屬性在函數中引用了哪一個 data 屬性?這個函數又是怎麼知道 data 屬性變了,並且只關心它內部引用的那個屬性,別的都無論?閉包
官方文檔對計算屬性的描述是:函數
文檔的描述讓個人困惑更加困惑,還有這種操做?這特麼是怎麼作到的?測試
Google 了一把,看了一篇三哥的博文(見文末),豁然開朗。this
咱們簡單模擬實現一個計算屬性:a 變化時,b 自動跟着變化。spa
因爲涉及 Vue 的響應式綁定的原理,若是你對此不熟,最好先看看《Vue.js 雙向綁定的實現原理》
雙向綁定
少囉嗦,先看過程:htm
1. 首先 b 屬性會被處理爲存取器屬性,訪問 b 就會觸發其 get 函數blog
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 節點之因此隨數據而變化,是由於節點依賴於數據,計算屬性之因此隨數據而變化,是由於計算屬性依賴於數據。作好響應式的關鍵就在於處理好依賴關係。
參考文章:https://skyronic.com/blog/vuejs-internals-computed-properties