data 和 computed 的區別

這樣看來,data 和 computed 在功能上似乎沒有任何區別。
data 和 computed 最核心區別
先一言以蔽之,data 和 computed 最核心的區別在於 data 中的屬性並不會隨賦值變量的改動而改動,而computed 會。(賦值變量類似:num: aaa.bbb,直接賦值是 num: 123)。下面有兩個例子來佐證。
第一個例子
<div id="app"> <h2>num1是data中的變量,其初始值為:{{num1}}</h2> <h2>點擊按鈕后,data中的num1變化為:{{num1}}</h2> <h2>點擊按鈕后,computed中的c_num1變化為:{{c_num}}</h2> <button @click="outerNumChange">給num1+10</button> <hr> <h1>1.data定義的屬性不會因為它的賦值變量的變化而變化</h1> <h1>2.computed定義的屬性會隨它的賦值變量的變化而變化</h1> </div> <script> let outer_obj = {num: 30} let app = new Vue({ el: "#app", data: { temp: outer_obj, // 這一句一定要加,必須在 data 對象上存在才能讓 Vue 將它轉換為響應式的,見下圖官方文檔 num1: outer_obj.num }, computed: { c_num () { return outer_obj.num } }, methods: { outerNumChange () { outer_obj.num += 10 } }, }) </script>

第二個例子
- 父組件改變 props,子組件如果直接使用 props,會觸發子組件更新
2. 父組件改變 props,子組件如果將 props 放進 data 中 再使用,不會觸發子組件更新
3. 父組件改變 props,子組件如果將 props 放進 computed 中再使用,會觸發子組件更新
代碼的例子如下
<div id="app"> <h2>父組件的 msg---{{msg}}</h2> <button @click="handleClick">父組件改變 props</button> <temp-comp :father-msg="msg"></temp-comp> </div> <script> Vue.component('temp-comp', { template: ` <div> <h2>直接使用 props---{{fatherMsg}}</h2> <h2>將 props 放進 data 再使用---{{dataFatherMsg}}</h2> <h2>將 props 放進 computed 再使用---{{computedFatherMsg}}</h2> </div> `, props: ['fatherMsg'], data () { return { dataFatherMsg: this.fatherMsg } }, computed: { computedFatherMsg () { return this.fatherMsg } } }) let app = new Vue({ el: "#app", data: { msg: "hello" }, methods: { handleClick () { this.msg += " world" } } }) </script>
再回到第一張圖,這里 data 里聲明函數的話,其實就和 methods 一模一樣了,根據官網的描述,計算屬性是基於它們的響應式依賴進行緩存的。這句話比較抽象,意思就是只要計算屬性依賴的那個數據不變,計算屬性就不會重新計算,而 methods 是只要頁面有任何數據變化導致數據的更新,methods 就會重新計算。官網沒有給出實例,這里給出一個簡短的例子。
<div id="app"> {{now()}}-----{{now2}}-----{{num}} <br> <button @click="hancleClick">改變 num</button> </div> <script> let app = new Vue({ el: "#app", data: { num: 10, now () { return Date.now() } }, computed: { now2 () { return Date.now() } }, methods: { hancleClick () { this.num += 10 } } }) </script>
換一個角度來理解 data 和 computed 之間的區別
考慮一下特殊情況
data: { foo () { return this.bar() + 1 }, bar () { return this.foo() + 1 } } // 這樣的話就是循環引用,無解
為了解決這個問題,Vue 把數據抽象成了兩層,第一層就是簡單的數據(data),第二層就是 computed (依賴於 data,也就是依賴於前一層)。第二層可以引用第一層的數據,而第一層卻不能引用第二層的數據。這也是為什么在 data 中不能引用 computed 中的數據的原因。
其實歸根結底就是一個 Vue 實例在渲染的時候數據解析的順序問題,結論是props->methods->data->computed->watch->created。官網的源碼也寫的很清楚,見下圖

源碼的鏈接在這里Vue源碼
https://github.com/vuejs/vue/blob/dev/src/core/instance/state.js#L48-L62