computed與watch的區(qū)別

如果一個值依賴多個屬性(多對一)袱耽,用computed肯定是更加方便的。 如果一個值變化后會引起一系列操作,或者一個值變化會引起一系列值的變化(一對多)澄峰,用watch更加方便一些。 watch 支持異步代碼而computed 不支持

1.計算屬性 computed

特點:

  • 支持緩存辟犀,只有依賴數(shù)據(jù)發(fā)生改變俏竞,才會重新進行計算;
  • 不支持異步堂竟,當 computed 內(nèi)有異步操作時無效魂毁,無法監(jiān)聽數(shù)據(jù)的變化;
  • computed 屬性值會默認走緩存出嘹,計算屬性是基于它們的響應式依賴進行緩存的席楚。也就是基 于 data 中聲明過或者父組件傳遞的 props 中的數(shù)據(jù)通過計算得到的值;
  • 如果一個屬性是由其他屬性計算而來的税稼,這個屬性依賴其他屬性 是一個多對一或者一對一酣胀,一般用computed;
  • 如果 computed 屬性值是函數(shù)娶聘,那么默認會走 get 方法闻镶,函數(shù)的返回值就是屬性的屬性值;在computed中的丸升,屬性都有一個get和一個 set 方法铆农,當數(shù)據(jù)變化時,調(diào)用 set 方法;

使用例子:

<template>
  <div>
    <span>{{testName}}</span>
    <el-input v-model="firstText"></el-input>
    <el-input v-model="lastText"></el-input>
    <el-input v-model="mergeText1"></el-input>
    <el-input v-model="mergeText2"></el-input>
    <div>{{fullNameFun()}}</div>
  </div>
</template>
<script>
import { defineComponent, computed, ref } from 'vue'
export default defineComponent({
  setup() {
    let firstText = ref('hello')
    let lastText = ref('world')
    const mergeText1 = computed(() => firstText.value + ' '  + lastText.value)
    const mergeText2 = computed({
      // getter
      get() {
        // 回調(diào)函數(shù) 當需要讀取當前屬性值時執(zhí)行墩剖,根據(jù)相關(guān)數(shù)據(jù)計算并返回當前屬性的值
        return `${firstText.value} ${lastText.value}`
      },
      // setter
      set(val) {
        //監(jiān)視當前屬性值的變化猴凹,當屬性值發(fā)生變化時執(zhí)行,更新相關(guān)的屬性數(shù)據(jù),val就是fullName的最新屬性值
        const names = val.split(' ')
        console.log(names)
        firstText.value = names[0]
        lastText.value = names[names.length - 1]
      },
    })
    
    function fullNameFun(){
      return firstText.value+ ' ' + lastText.value
    }
    
    return {
      firstText,
      lastText,
      mergeText1,
      mergeText2,
      fullNameFun
    }
  }
})
</script>

優(yōu)點:

  • 當改變 ref 或者 reactive 響應式變量值時岭皂,整個應用會重新渲染郊霎,vue 會被數(shù)據(jù)重新渲染到 dom 中。這時爷绘,如果我們模板中使用了 methods 中的fullNameFun函數(shù)书劝,或者使用了組合式return的函數(shù)。隨著渲染土至,方法也會被調(diào)用购对。但是 如果computed中所依賴的變量沒有發(fā)生改變,則不會進行重新的計算陶因,從而性能開銷比較小骡苞。當新的值需要大量計算才能得到,緩存的意義就非常大楷扬;
  • 如果 computed 所依賴的數(shù)據(jù)發(fā)生改變時解幽,計算屬性才會重新計算,并進行緩存烘苹;當改變其他數(shù)據(jù)時躲株,computed 屬性 并不會重新計算,從而提升性能螟加;
  • 當拿到的值需要進行一定處理使用時徘溢,就可以使用 computed;

2. 偵聽屬性 watch (vue3中還有watcheffect詳細講解捆探,在另外一篇文章中傳送門

特點:

  • 完全等同于vue2 中的watch
  • 不支持緩存然爆,數(shù)據(jù)變化,直接會觸發(fā)相應的操作黍图;
  • watch 支持異步操作曾雕;
  • 監(jiān)聽的函數(shù)接收兩個參數(shù),第一個參數(shù)是最新的值助被;第二個參數(shù)是輸入之前的值剖张;
    當一個屬性發(fā)生變化時,需要執(zhí)行對應的操作揩环,一對多搔弄;
  • 監(jiān)聽數(shù)據(jù)必須是 data 中聲明過或者組合式api中聲明的響應式值或者父組件傳遞過來的 props 中的數(shù)據(jù)。當數(shù)據(jù)變化時觸發(fā)其他操作丰滑,函數(shù)有兩個參數(shù):
  • immediate:組件加載立即觸發(fā)回調(diào)函數(shù)執(zhí)行顾犹;
  • deep: 深度監(jiān)聽;為了發(fā)現(xiàn)對象內(nèi)部值的變化,復雜類型的數(shù)據(jù)時使用炫刷,例如:數(shù)組中的對象內(nèi)容的改變擎宝,注意:監(jiān)聽數(shù)組的變動不需要這么做。注意:deep無法監(jiān)聽到數(shù)組的變動和對象的新增浑玛,參考vue數(shù)組變異,只有以響應式的方式觸發(fā)才會被監(jiān)聽到绍申;

注:當需要在數(shù)據(jù)變化時執(zhí)行異步或開銷較大的操作時,這個方式是最有用的顾彰,這是和 computed 最大的區(qū)別极阅。

2.1 一般用法,監(jiān)聽單個變量或多個數(shù)據(jù)源或者一個函數(shù)返回值

注:監(jiān)聽一個函數(shù)的返回值拘央,當函數(shù)里面中所用到的變量發(fā)生變化都會觸發(fā)回調(diào)

// 偵聽一個 getter
const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount) => {
    /* ... */
  }
)
// 直接偵聽一個 reactive
const count = ref(0)
watch(state , (newValue, oldValue) => {
  /* ... */
})

// 直接偵聽一個 ref
const count = ref(0)
watch(count, (count, prevCount) => {
  /* ... */
})

// 監(jiān)聽多個數(shù)據(jù)源
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
  /* ... */
})

// watch 可以監(jiān)聽一個函數(shù)的返回值
watch(() => {
   return otherName.firstName + otherName.lastName
},
   value => {
   // 當otherName中的 firstName或者lastName發(fā)生變化時涂屁,都會進入這個函數(shù)
   console.log(`我叫${value}`)
  }
)

2.2 監(jiān)聽復雜數(shù)據(jù)(深度監(jiān)聽 deep)

不使用 deep 時书在,當我們改變 obj.a 的值時灰伟,watch 不能監(jiān)聽到數(shù)據(jù)變化,默認情況下儒旬,watch 只監(jiān)聽屬性引用的變化栏账,也就是只監(jiān)聽了一層,但改對象內(nèi)部的屬性是監(jiān)聽不到的栈源。
immerdiate 屬性: 通過聲明 immediate 選項為 true挡爵,可以立即執(zhí)行一次 watch里面的函數(shù)。

import { watch, ref, reactive } from 'vue'

export default {
  setup() {
   let obj= reactive({
        text:'hello'
    })
    watch(obj, (newValue, oldValue) => {
      // 回調(diào)函數(shù)
    }, {
      immediate: true,
      deep: true
    })
    return {
      obj
    }
  }
}

通過使用 deep: true 進行深入觀察甚垦,我們監(jiān)聽 obj茶鹃,會把 obj 下面的屬性層層遍歷,都加上監(jiān)聽事件艰亮,這樣做性能開銷也會變大闭翩,只要修改 obj 中任意屬性值,都會觸發(fā)回調(diào)迄埃,那么如何優(yōu)化性能呢疗韵?
可以直接對用對象 . 屬性的方法拿到屬性,也就是上面說道的偵聽一個 getter

import { watch, ref, reactive } from 'vue-router'

export default {
  setup() {
   let obj= reactive({
        text:'hello'
    })
    watch(()=>obj.text, (newValue, oldValue) => {
      // 回調(diào)函數(shù)
    }, {
      immediate: true,
      deep: true
    })
    return {
      obj
    }
  }
}

注意事項:

  • watch 中的函數(shù)名稱必須是所依賴 data 中的屬性名稱;(vue2)
  • watch 中的函數(shù)是不需要調(diào)用的侄非,只要函數(shù)所依賴的屬性發(fā)生了改變 那么相對應的函數(shù)就會執(zhí)行蕉汪;
  • watch 中的函數(shù)會有2個參數(shù) 一個是新值,一個是舊值逞怨;
  • watch 默認情況下無法監(jiān)聽對象的改變者疤,如果需要進行監(jiān)聽則需要進行深度監(jiān)聽 深度監(jiān)聽需要配置 handler(vue2中才需要) 函數(shù)以及 deep 為true。(因為它只會監(jiān)聽對象的地址是否發(fā)生了改變叠赦,而值是不會監(jiān)聽的)驹马;(vue2) 在vue3中有些許區(qū)別。在另外一篇文章中再說
  • watch 默認情況下第一次的時候不會去做監(jiān)聽,如果需要在第一次加載的時候也需要去做監(jiān)聽的話需要設置 immediate:true窥翩;

vue2中數(shù)組響應式原理:
1 重新定義原生數(shù)組方法push unshift shift pop splice sort reverse 因為這些方法可以修改原數(shù)組业岁。
2 拿到原生數(shù)組方法 Object.create(Array.prototype)
3 AOP攔截,再執(zhí)行重寫數(shù)組方法前,先執(zhí)行原生數(shù)組方法

watch 在特殊情況下是無法監(jiān)聽到數(shù)組的變化

所以,vue2中對數(shù)組的解決方案:

  • 通過下標來更改數(shù)組中的數(shù)據(jù)寇蚊;
  • 通過 length 來改變數(shù)組的長度笔时;

通過 Vue 實例方法 set 進行設置 $set( target, propertyName/index, value)
參數(shù): target {Object | Array}propertyName/index {string | number}仗岸, value {any}

this.$set(this.arr,0,100);

通過 splice 來數(shù)組清空 $delete( target, propertyName/index )
參數(shù):target {Object | Array} 允耿, propertyName/index {string | number}

this.$delete(this.arr,0)

vue2中深度監(jiān)聽對應的函數(shù)名必須為 handler ,否則無效果,因為 watche r里面對應的是對 handler 的調(diào)用

劃重點:在vue3中利用的是ES6的proxy,對數(shù)據(jù)響應式進行一個數(shù)據(jù)的代理扒怖,可以監(jiān)控到數(shù)組的變化较锡。vue3中如果想要讓一個對象變?yōu)轫憫綌?shù)據(jù),可以使用reactiveref盗痒。因此$set在vue3中廢棄

3. 方法 methods

methods 跟前面的都不一樣蚂蕴,我們通常在這里寫入方法,只要調(diào)用就會重新執(zhí)行一次俯邓,相應的有一些觸發(fā)條件骡楼,在某些時候 methodscomputed 看不出來具體的差別,但是一旦在運算量比較復雜的頁面中稽鞭,就會體現(xiàn)出不一樣鸟整。
注意:computed 是具有緩存的,這就意味著只要計算屬性的依賴沒有進行相應的數(shù)據(jù)更新朦蕴,那么 computed 會直接從緩存中獲取值篮条,多次訪問都會返回之前的計算結(jié)果。

總結(jié)

在 computed 和 watch 方面吩抓,一個是計算涉茧,一個是觀察,在語義上是有區(qū)別的琴拧。
計算是通過變量計算來得出數(shù)據(jù)降瞳,而觀察是觀察一個特定的值,根據(jù)被觀察者的變動進行相應的變化蚓胸,在特定的場景下不能相互混用挣饥,所以還是需要注意 api 運用的合理性和語義性。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末沛膳,一起剝皮案震驚了整個濱河市扔枫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锹安,老刑警劉巖短荐,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件倚舀,死亡現(xiàn)場離奇詭異,居然都是意外死亡忍宋,警方通過查閱死者的電腦和手機痕貌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來糠排,“玉大人舵稠,你說我怎么就攤上這事∪牖拢” “怎么了哺徊?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長乾闰。 經(jīng)常有香客問我落追,道長,這世上最難降的妖魔是什么涯肩? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任轿钠,我火速辦了婚禮,結(jié)果婚禮上宽菜,老公的妹妹穿的比我還像新娘谣膳。我一直安慰自己竿报,他們只是感情好铅乡,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著烈菌,像睡著了一般阵幸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上芽世,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天挚赊,我揣著相機與錄音,去河邊找鬼济瓢。 笑死荠割,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的旺矾。 我是一名探鬼主播蔑鹦,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼箕宙!你這毒婦竟也來了嚎朽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤柬帕,失蹤者是張志新(化名)和其女友劉穎哟忍,沒想到半個月后狡门,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡锅很,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年其馏,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片爆安。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡尝偎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鹏控,到底是詐尸還是另有隱情致扯,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布当辐,位于F島的核電站抖僵,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏缘揪。R本人自食惡果不足惜耍群,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望找筝。 院中可真熱鬧蹈垢,春花似錦、人聲如沸袖裕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽急鳄。三九已至谤民,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間疾宏,已是汗流浹背张足。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坎藐,地道東北人为牍。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像岩馍,于是被迫代替她去往敵國和親碉咆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容