Vue中的computed和watch的原理解析
一、核心基礎(chǔ):響應(yīng)式系統(tǒng)支撐
computed與watch的實(shí)現(xiàn)均依賴Vue響應(yīng)式核心——依賴收集與觸發(fā)更新:
- 響應(yīng)式數(shù)據(jù)通過(guò)
Object.defineProperty(Vue2)或Proxy(Vue3)劫持 getter/setter; - 讀取數(shù)據(jù)時(shí)收集依賴(記錄使用該數(shù)據(jù)的組件/計(jì)算屬性);
- 修改數(shù)據(jù)時(shí)觸發(fā)setter,通知所有依賴執(zhí)行更新邏輯。
二者本質(zhì)是響應(yīng)式系統(tǒng)的“上層應(yīng)用”,差異在于對(duì)依賴變化的處理邏輯。
二、computed:帶緩存的依賴推導(dǎo)
2.1 核心原理:緩存+懶執(zhí)行
computed是“派生值”計(jì)算器,核心特性是依賴不變則復(fù)用緩存,避免重復(fù)計(jì)算:
- 依賴收集:首次訪問(wèn)computed時(shí),執(zhí)行其getter函數(shù),收集依賴的響應(yīng)式數(shù)據(jù);
- 緩存結(jié)果:將計(jì)算結(jié)果緩存,標(biāo)記為“清潔”狀態(tài);
- 懶更新:僅當(dāng)依賴數(shù)據(jù)變化時(shí),才標(biāo)記為“臟”狀態(tài),下次訪問(wèn)時(shí)重新計(jì)算并更新緩存。
2.2 簡(jiǎn)化實(shí)現(xiàn)代碼
// 模擬computed核心邏輯(Vue3風(fēng)格)
class ComputedRef {
constructor(getter, ctx) {
this.getter = getter; // 計(jì)算函數(shù)
this.ctx = ctx; // 上下文
this._value = null; // 緩存值
this._dirty = true; // 臟標(biāo)記:true需重新計(jì)算
}
// 訪問(wèn)computed時(shí)觸發(fā)
get value() {
if (this._dirty) {
this._value = this.getter.call(this.ctx); // 執(zhí)行計(jì)算
this._dirty = false; // 標(biāo)記為清潔
}
return this._value; // 復(fù)用緩存
}
// 依賴變化時(shí)調(diào)用
markDirty() {
this._dirty = true; // 標(biāo)記為臟
}
}
// 實(shí)際使用
const count = ref(1);
// 計(jì)算屬性:依賴count
const doubleCount = new ComputedRef(() => count.value * 2, this);
console.log(doubleCount.value); // 2(計(jì)算并緩存)
console.log(doubleCount.value); // 2(直接復(fù)用緩存)
count.value = 2; // 觸發(fā)count的setter,調(diào)用doubleCount.markDirty()
console.log(doubleCount.value); // 4(重新計(jì)算)三、watch:數(shù)據(jù)變化的副作用觸發(fā)器
3.1 核心原理:監(jiān)聽(tīng)變化+執(zhí)行回調(diào)
watch是“數(shù)據(jù)監(jiān)聽(tīng)器”,核心是監(jiān)聽(tīng)指定數(shù)據(jù)源變化,觸發(fā)自定義副作用(如異步請(qǐng)求、DOM操作),支持深度監(jiān)聽(tīng)和立即執(zhí)行。
3.2 關(guān)鍵特性與實(shí)現(xiàn)
// 模擬watch核心邏輯(Vue3風(fēng)格)
function watch(source, callback, options = {}) {
const { immediate = false, deep = false } = options;
let oldValue;
// 1. 初始化:獲取初始值
const getInitialValue = () => {
// 深度監(jiān)聽(tīng)時(shí)遞歸收集對(duì)象所有屬性依賴
if (deep && isObject(source.value)) {
traverse(source.value);
}
return source.value;
};
// 2. 副作用函數(shù):數(shù)據(jù)變化時(shí)執(zhí)行
const effectFn = () => {
const newValue = source.value;
callback(newValue, oldValue); // 觸發(fā)回調(diào)
oldValue = newValue;
};
// 3. 立即執(zhí)行(immediate為true時(shí))
if (immediate) {
oldValue = getInitialValue();
effectFn();
} else {
oldValue = getInitialValue();
}
// 4. 關(guān)聯(lián)響應(yīng)式數(shù)據(jù):依賴變化時(shí)觸發(fā)effectFn
effect(effectFn, { lazy: false });
}
// 實(shí)際使用
const user = reactive({ name: '張三', age: 20 });
// 監(jiān)聽(tīng)user.age,支持深度監(jiān)聽(tīng)
watch(
() => user.age,
(newAge, oldAge) => {
console.log(`年齡從${oldAge}變?yōu)?{newAge}`);
},
{ immediate: true, deep: false }
);深度監(jiān)聽(tīng)(deep: true)通過(guò)遞歸遍歷對(duì)象屬性實(shí)現(xiàn),會(huì)收集所有子屬性依賴,性能消耗較高,非必要不使用。
四、核心差異與適用場(chǎng)景
| 維度 | computed | watch |
|---|---|---|
| 核心機(jī)制 | 依賴推導(dǎo),緩存結(jié)果 | 監(jiān)聽(tīng)變化,觸發(fā)副作用 |
| 緩存特性 | 有緩存,依賴不變不計(jì)算 | 無(wú)緩存,變化即觸發(fā) |
| 返回值 | 必須返回值(派生數(shù)據(jù)) | 無(wú)需返回值(執(zhí)行操作) |
| 適用場(chǎng)景 | 數(shù)據(jù)格式化、多值計(jì)算(如總價(jià)=單價(jià)×數(shù)量) | 異步操作、數(shù)據(jù)變化后的復(fù)雜邏輯(如刷新列表) |
五、實(shí)戰(zhàn)避坑要點(diǎn)
- computed避免副作用:getter中不可執(zhí)行異步操作或修改DOM,否則會(huì)破壞緩存邏輯和響應(yīng)式追蹤。
- watch精簡(jiǎn)監(jiān)聽(tīng)源:盡量監(jiān)聽(tīng)具體屬性(如()=>user.age)而非整個(gè)對(duì)象,減少深度監(jiān)聽(tīng)的性能損耗。
- Vue3注意點(diǎn):watch監(jiān)聽(tīng)reactive對(duì)象時(shí),默認(rèn)開(kāi)啟深度監(jiān)聽(tīng);監(jiān)聽(tīng)ref時(shí)需通過(guò).value訪問(wèn)。
- 緩存失效場(chǎng)景:computed依賴非響應(yīng)式數(shù)據(jù)(如普通變量)時(shí),數(shù)據(jù)變化不會(huì)觸發(fā)重新計(jì)算。
到此這篇關(guān)于Vue中的computed和watch的原理解析的文章就介紹到這了,更多相關(guān)vue computed和watch原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- vue中computed順序、watch順序、響應(yīng)次數(shù)使用
- Vue3中Watch、Watcheffect、Computed的使用和區(qū)別解析
- Vue中的methods、computed計(jì)算屬性和watch監(jiān)聽(tīng)屬性的使用和區(qū)別解析
- Vue Computed中g(shù)et和set的用法及Computed與watch的區(qū)別
- Vue中computed和watch的區(qū)別
- Vue中computed屬性和watch,methods的區(qū)別
- Vue中的computed和watch用法及區(qū)別
- Vue3中的setup語(yǔ)法糖、computed函數(shù)、watch函數(shù)詳解
- Vue computed與watch用法區(qū)分
相關(guān)文章
實(shí)現(xiàn)一個(gè) Vue 吸頂錨點(diǎn)組件方法
這篇文章主要介紹了實(shí)現(xiàn)一個(gè) Vue 吸頂錨點(diǎn)組件方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
Vue+Router+Element實(shí)現(xiàn)簡(jiǎn)易導(dǎo)航欄
這篇文章主要為大家詳細(xì)介紹了Vue+Router+Element實(shí)現(xiàn)簡(jiǎn)易導(dǎo)航欄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
Vue.js中關(guān)于偵聽(tīng)器(watch)的高級(jí)用法示例
Vue.js 提供了一個(gè)方法 watch,它用于觀察Vue實(shí)例上的數(shù)據(jù)變動(dòng)。下面這篇文章主要給大家介紹了關(guān)于Vue.js中關(guān)于偵聽(tīng)器(watch)的高級(jí)用法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2018-05-05
vue-element-admin登錄攔截設(shè)置白名單方式
這篇文章主要介紹了vue-element-admin登錄攔截設(shè)置白名單方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
rem實(shí)現(xiàn)響應(yīng)式布局的思路詳解
這篇文章主要為大家介紹了rem實(shí)現(xiàn)響應(yīng)式布局的思路詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
vue實(shí)現(xiàn)移動(dòng)端觸屏拖拽功能
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)移動(dòng)端觸屏拖拽功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08

