1,計算屬性的用法
vue中計算屬性能夠實現一個數據依賴其他數據的變化而變化,話不多說先上代碼
1 new Vue({ 2 data:{ 3 a:1 4 }, 5 mounted(){ 6 const that = this 7 setTimeout(function(){ 8 that.a = 2 9 },2000) 10 }, 11 computed:{ 12 b:function(){ 13 console.log("現在b的值是",this.a+1) 14 return this.a + 1 15 } 16 } 17 })
在computed中定義一個 計算屬性(函數),這個函數中涉及到data中的所有數據,都會被收集起來,將他們作為這個屬性計算的依賴,當這些依賴發生變化時,就會執行這個計算屬性對應的函數。比如上面的例子中,b的計算屬性函數中有this.a,a是data中的數據,那a將會作為b計算屬性的一個依賴被收集起來,第8行中that.a = 2,此時a的值發生變化,觸發b的計算屬性函數,這樣就完成了一次計算。
2,計算屬性的原理
有這么一個方法 Object.defineProperty()
,先讓我們看看這個方法是怎么用的。
Object.defineProperty()
方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,並返回此對象。
Object.defineProperty(obj, prop, descriptor)
參數:
-
obj
要定義屬性的對象。 -
prop
要定義或修改的屬性的名稱或Symbol
。 -
descriptor
要定義或修改的屬性描述符。 -
其中第三個參數descriptor是一個json,有興趣的可以去
Object.defineProperty()
研究一下。我們這里主要是看set(屬性的setter函數),get(屬性的getter函數) - 話不多說,先上代碼
var obj = {} Object.defineProperty(obj,"a",{ set:function(val){ console.log("set函數執行") this._a = val // 定義一個_a作為一個私有屬性,來記錄a屬性的值 }, get:function(){ console.log("get函數執行") return this._a } }) obj.a = "123" // set函數執行 console.log(obj.a) // get函數執行 // 123
上面的代碼 可以看出 只要執行obj.a = xxx 就會執行 obj中a屬性的set函數,只要執行obj.a 就會調用obj中a屬性的get函數
3,屬性計算的實現
vue中屬性計算利用函數閉包和對象屬性set,get函數 完美實現
1 var Dep = null 2 function defineReactive(obj,key,val){ 3 var deps = [] // deps 收集依賴用 4 Object.defineProperty(obj,key,{ 5 get:function(){ 6 if(Dep){ 7 deps.push(Dep) 8 } 9 return val 10 }, 11 set:function(newVal){ 12 val = newVal; 13 deps.forEach(func=>func()) // deps 在set函數中被引用 形成閉包 14 } 15 }) 16 } 17 18 function defineComputed(obj,key,func){ 19 func = func.bind(obj) 20 var value 21 Dep = function(){ 22 value = func() // value 在此函數中被引用 形成閉包 23 } 24 value = func() // 執行一次 屬性計算函數,計算屬性函數中的this.a(36行)的執行,會執行a的get函數(5行),將計算屬性函數放到依賴項中(第7行) 25 Dep = null 26 Object.defineProperty(obj,key,{ 27 get:function(){ 28 return value // value 在set函數中被引用 形成閉包 29 } 30 }) 31 } 32 33 var obj = {} 34 defineReactive(obj,"a",0) 35 defineComputed(obj,"b",function(){ 36 var a = this.a 37 return a + 1 38 })
執行上面的代碼,在控制台輸入
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);
測試一下,完美打印出 1, 2, 3, 4
通過對存取器屬性、閉包和觀察者模式的綜合運用,Vue 巧妙的實現了計算屬性。現在再看官方文檔描述,是不是更通透了呢。 可以看出,Vue 響應式系統的核心理念是“依賴”,DOM 節點之所以隨數據而變化,是因為節點依賴於數據,計算屬性之所以隨數據而變化,是因為計算屬性依賴於數據。做好響應式的關鍵就在於處理好依賴關系。