如何理解Vue中computed和watch的區別
概述
我們在 Vue 項目中多多少少都會有用到 computed 和 watch,這兩個看似都能實現對數據的監聽,但還是有區別。所以以下通過一個小栗子來理解一下這兩者的區別。
computed 計算屬性
計算屬性基於 data 中聲明過或者父組件傳遞的 props 中的數據通過計算得到的一個新值,這個新值隻會根據已知值的變化而變化,簡言之:這個屬性依賴其他屬性,由其他屬性計算而來的。
<p>姓名:{{ fullName }}</p> ... ... data: { firstName: 'David', lastName: 'Beckham' }, computed: { fullName: function() { //方法的返回值作為屬性值 return this.firstName + ' ' + this.lastName } }
在 computed 屬性對象中定義計算屬性的方法,和取data對象裡的數據屬性一樣以屬性訪問的形式調用,即在頁面中使用 {{ 方法名 }} 來顯示計算的結果。
註:計算屬性 fullName 不能在 data 中定義,而計算屬性值的相關已知值在data中;
如果 fullName 在 data 中定義瞭會報錯如下圖:
因為如果 computed 屬性值是一個函數,那麼默認會走get方法,必須要有一個返回值,函數的返回值就是屬性的屬性值。計算屬性定義瞭 fullName 並返回對應的結果給這個變量,變量不可被重復定義和賦值。
在官方文檔中,還強調瞭 computed 一個重要的特點,就是 computed 帶有緩存功能。比如我在頁面中多次顯示 fullName:
<p>姓名:{{ fullName }}</p> <p>姓名:{{ fullName }}</p> <p>姓名:{{ fullName }}</p> <p>姓名:{{ fullName }}</p> <p>姓名:{{ fullName }}</p> ... ... computed: { fullName: function () { console.log('computed') // 在控制臺隻打印瞭一次 return this.firstName + ' ' + this.lastName } }
我們知道 computed 內定義的 function 隻執行一次,僅當初始化顯示或者相關的 data、props 等屬性數據發生變化的時候調用;
而 computed 屬性值默認會緩存計算結果,計算屬性是基於它們的響應式依賴進行緩存的;
隻有當 computed 屬性被使用後,才會執行 computed 的代碼,在重復的調用中,隻要依賴數據不變,直接取緩存中的計算結果。隻有依賴型數據發生改變,computed 才會重新計算。
計算屬性的高級:
在computed 中的屬性都有一個 get 和一個set方法,當數據變化時,調用 set 方法。下面我們通過計算屬性的 getter/setter 方法來實現對屬性數據的顯示和監視,即雙向綁定。
computed: { fullName: { get() { //讀取當前屬性值的回調,根據相關的數據計算並返回當前屬性的值 return this.firstName + ' ' + this.lastName }, set(val) { // 當屬性值發生改變時回調,更新相關的屬性數據,val就是fullName的最新屬性值 const names = val ? val.split(' ') : []; this.firstName = names[0] this.lastName = names[1] } } }
watch 監聽屬性
通過 vm 對象的 $watch() 或 watch 配置來監聽 Vue 實例上的屬性變化,或某些特定數據的變化,然後執行某些具體的業務邏輯操作。當屬性變化時,回調函數自動調用,在函數內部進行計算。其可以監聽的數據來源:data,props,computed 內的數據。
以上示例通過 watch 來實現:
watch: { // 監聽 data 中的 firstName,如果發生瞭變化,就把變化的值給 data 中的 fullName, val 就是 firstName 的最新值 firstName: function(val) { this.fullName = val + ' ' + this.lastName }, lastName: function(val) { this.fullName = this.firstName + ' ' + val } } // 由上可以看出 watch 要監聽兩個數據,而且代碼是同類型的重復的,所以相比用 computed 更簡潔
註:監聽函數有兩個參數,第一個參數是最新的值,第二個參數是輸入之前的值,順序一定是新值,舊值,如果隻寫一個參數,那就是最新屬性值。
在使用時選擇 watch 還是 computed,還有一個參考點就是官網說的:當需要在數據變化時執行異步或開銷較大的操作時,watch方式是最有用的。所以 watch 一定是支持異步的。
上面僅限監聽簡單數據類型,監聽復雜數據類型就需要用到深度監聽 deep。
deep:為瞭發現對象內部值的變化,可以在選項參數中指定 deep: true。註意監聽數組的變更不需要這麼做。
data: { fullName: { firstName: 'David', lastName: 'Beckham' } }, watch: { fullName: { handler(newVal, oldVal) { console.log(newVal); console.log(oldVal); }, deep: true } }
以上打印結果:
打印出來的 newVal 和 oldVal 值是一樣的,所以深度監聽雖然可以監聽到對象的變化,但是無法監聽到對象裡面哪個具體屬性的變化。這是因為它們的引用指向同一個對象/數組。Vue 不會保留變更之前值的副本。[ vm.$watch 深度監聽 ]
若果要監聽對象的單個屬性的變化,有兩種方法:
1. 直接監聽對象的屬性
watch:{ fullName.firstName: function(newVal,oldVal){ console.log(newVal,oldVal); } }
2. 與 computed 屬性配合使用,computed 返回想要監聽的屬性值,watch 用來監聽
computed: { firstNameChange() { return this.fullName.firstName } }, watch: { firstNameChange() { console.log(this.fullName) } }
總結
watch和computed都是以Vue的依賴追蹤機制為基礎的,當某一個依賴型數據(依賴型數據:簡單理解即放在 data 等對象下的實例數據)發生變化的時候,所有依賴這個數據的相關數據會自動發生變化,即自動調用相關的函數,來實現數據的變動。
當依賴的值變化時,在watch中,是可以做一些復雜的操作的,而computed中的依賴,僅僅是一個值依賴於另一個值,是值上的依賴。
應用場景:
computed:用於處理復雜的邏輯運算;一個數據受一個或多個數據影響;用來處理watch和methods無法處理的,或處理起來不方便的情況。例如處理模板中的復雜表達式、購物車裡面的商品數量和總金額之間的變化關系等。
watch:用來處理當一個屬性發生變化時,需要執行某些具體的業務邏輯操作,或要在數據變化時執行異步或開銷較大的操作;一個數據改變影響多個數據。例如用來監控路由、inpurt 輸入框值的特殊處理等。
區別:
computed
- 初始化顯示或者相關的 data、props 等屬性數據發生變化的時候調用;
- 計算屬性不在 data 中,它是基於data 或 props 中的數據通過計算得到的一個新值,這個新值根據已知值的變化而變化;
- 在 computed 屬性對象中定義計算屬性的方法,和取data對象裡的數據屬性一樣,以屬性訪問的形式調用;
- 如果 computed 屬性值是函數,那麼默認會走 get 方法,必須要有一個返回值,函數的返回值就是屬性的屬性值;
- computed 屬性值默認會緩存計算結果,在重復的調用中,隻要依賴數據不變,直接取緩存中的計算結果,隻有依賴型數據發生改變,computed 才會重新計算;
- 在computed中的,屬性都有一個 get 和一個 set 方法,當數據變化時,調用 set 方法。
watch
- 主要用來監聽某些特定數據的變化,從而進行某些具體的業務邏輯操作,可以看作是 computed 和 methods 的結合體;
- 可以監聽的數據來源:data,props,computed內的數據;
- watch支持異步;
- 不支持緩存,監聽的數據改變,直接會觸發相應的操作;
- 監聽函數有兩個參數,第一個參數是最新的值,第二個參數是輸入之前的值,順序一定是新值,舊值。
以上就是如何理解Vue中computed和watch的區別的詳細內容,更多關於Vue的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- vue Watch和Computed的使用總結
- Vue計算屬性與監視(偵聽)屬性的使用深度學習
- Vue中的watch是什麼以及watch和computed的區別
- vue2.x版詳解computed和watch的使用
- 簡單聊聊Vue中的計算屬性和屬性偵聽