Vue中的Computed實(shí)現(xiàn)原理分析
在 Vue.js 中,computed 屬性是一種強(qiáng)大的特性,用于定義依賴于其他響應(yīng)式數(shù)據(jù)的計(jì)算值。
computed 屬性不僅能夠簡(jiǎn)化模板中的表達(dá)式,還能夠緩存計(jì)算結(jié)果,避免不必要的重復(fù)計(jì)算,從而提高性能。
將深入探討 Vue 中 computed 屬性的實(shí)現(xiàn)原理,包括其工作機(jī)制、依賴追蹤、緩存策略等方面。
1. Computed 屬性概述
Computed 屬性是 Vue 實(shí)例中的一個(gè)特殊屬性,它允許開(kāi)發(fā)者定義一個(gè)計(jì)算值,該值依賴于其他響應(yīng)式數(shù)據(jù)。
Computed 屬性具有以下特點(diǎn):
- 響應(yīng)式:當(dāng)依賴的數(shù)據(jù)發(fā)生變化時(shí),computed 屬性會(huì)自動(dòng)重新計(jì)算。
- 緩存:computed 屬性會(huì)緩存計(jì)算結(jié)果,只有當(dāng)依賴的數(shù)據(jù)發(fā)生變化時(shí),才會(huì)重新計(jì)算。
- 惰性求值:computed 屬性在首次訪問(wèn)時(shí)才會(huì)進(jìn)行計(jì)算,之后會(huì)根據(jù)依賴數(shù)據(jù)的變化情況決定是否重新計(jì)算。
2. Computed 屬性的基本用法
在 Vue 實(shí)例中,可以通過(guò) computed 選項(xiàng)來(lái)定義 computed 屬性。
new Vue({
data() {
return {
firstName: 'John',
lastName: 'Doe'
};
},
computed: {
fullName() {
return `${this.firstName} ${this.lastName}`;
}
}
});在上述代碼中,fullName 是一個(gè) computed 屬性,它依賴于 firstName 和 lastName。
當(dāng) firstName 或 lastName 發(fā)生變化時(shí),fullName 會(huì)自動(dòng)重新計(jì)算。
3. Computed 屬性的實(shí)現(xiàn)原理
3.1 依賴追蹤
Vue 的 computed 屬性實(shí)現(xiàn)依賴于 Vue 的響應(yīng)式系統(tǒng)。
Vue 通過(guò) Object.defineProperty 或 Proxy 來(lái)劫持?jǐn)?shù)據(jù)的變化,并在數(shù)據(jù)變化時(shí)通知依賴該數(shù)據(jù)的觀察者。
3.1.1 響應(yīng)式數(shù)據(jù)劫持
Vue 在初始化數(shù)據(jù)時(shí),會(huì)通過(guò) Object.defineProperty 或 Proxy 對(duì)數(shù)據(jù)進(jìn)行劫持,使其變?yōu)轫憫?yīng)式數(shù)據(jù)。
function defineReactive(obj, key, val) {
const dep = new Dep();
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
if (Dep.target) {
dep.depend();
}
return val;
},
set(newVal) {
if (newVal === val) return;
val = newVal;
dep.notify();
}
});
}在上述代碼中,defineReactive 函數(shù)通過(guò) Object.defineProperty 劫持了對(duì)象的屬性,并在 get 和 set 方法中分別收集和通知依賴。
3.1.2 依賴收集
在 computed 屬性被訪問(wèn)時(shí),Vue 會(huì)通過(guò) Dep.target 來(lái)收集依賴。
functionWatcher(vm, expOrFn, cb) {
this.vm = vm;
this.getter = parsePath(expOrFn);
this.cb = cb;
this.value = this.get();
}
Watcher.prototype.get = function() {
Dep.target = this;
const value = this.getter.call(this.vm, this.vm);
Dep.target = null;
return value;
};
Watcher.prototype.update = function() {
const oldValue = this.value;
this.value = this.get();
this.cb.call(this.vm, this.value, oldValue);
};在上述代碼中,Watcher 實(shí)例在 get 方法中將自身設(shè)置為 Dep.target,然后訪問(wèn) computed 屬性,從而觸發(fā)依賴數(shù)據(jù)的 get 方法,完成依賴收集。
3.2 緩存策略
Computed 屬性具有緩存機(jī)制,只有在依賴數(shù)據(jù)發(fā)生變化時(shí),才會(huì)重新計(jì)算。
3.2.1 緩存實(shí)現(xiàn)
Vue 通過(guò) Watcher 實(shí)例的 dirty 屬性來(lái)控制緩存。
function Watcher(vm, expOrFn, cb, options) {
this.vm = vm;
this.getter = expOrFn;
this.cb = cb;
this.dirty = this.lazy = !!options.lazy;
this.value = this.lazy ? undefined : this.get();
}
Watcher.prototype.evaluate = function() {
this.value = this.get();
this.dirty = false;
};
Watcher.prototype.get = function() {
pushTarget(this);
let value;
const vm = this.vm;
try {
value = this.getter.call(vm, vm);
} finally {
popTarget();
}
return value;
};
Watcher.prototype.update = function() {
if (this.lazy) {
this.dirty = true;
} else {
this.run();
}
};在上述代碼中,Watcher 實(shí)例的 dirty 屬性用于標(biāo)記 computed 屬性是否需要重新計(jì)算。
當(dāng)依賴數(shù)據(jù)發(fā)生變化時(shí),Watcher 的 update 方法會(huì)將 dirty 設(shè)置為 true,表示需要重新計(jì)算。
3.2.2 惰性求值
Computed 屬性在首次訪問(wèn)時(shí)才會(huì)進(jìn)行計(jì)算,之后會(huì)根據(jù) dirty 屬性決定是否重新計(jì)算。
function createComputedGetter(key) {
return function computedGetter() {
const watcher = this._computedWatchers && this._computedWatchers[key];
if (watcher) {
if (watcher.dirty) {
watcher.evaluate();
}
if (Dep.target) {
watcher.depend();
}
return watcher.value;
}
};
}在上述代碼中,createComputedGetter 函數(shù)返回一個(gè) computed 屬性的 getter 函數(shù)。
在訪問(wèn) computed 屬性時(shí),如果 dirty 為 true,則會(huì)調(diào)用 watcher.evaluate 方法進(jìn)行計(jì)算,并將 dirty 設(shè)置為 false,表示計(jì)算結(jié)果已緩存。
4. Computed 屬性的優(yōu)化
4.1 避免不必要的計(jì)算
在定義 computed 屬性時(shí),應(yīng)盡量避免不必要的計(jì)算。
例如,如果 computed 屬性的計(jì)算邏輯較為復(fù)雜,可以考慮將其拆分為多個(gè)簡(jiǎn)單的 computed 屬性。
computed: {
fullName() {
return `${this.firstName} ${this.lastName}`;
},
formattedName() {
return this.fullName.toUpperCase();
}
}4.2 使用 Watcher 進(jìn)行性能優(yōu)化
在某些情況下,可以使用 watch 選項(xiàng)來(lái)替代 computed 屬性,以實(shí)現(xiàn)更細(xì)粒度的控制和性能優(yōu)化。
watch: {
firstName: 'updateFullName',
lastName: 'updateFullName'
},
methods: {
updateFullName() {
this.fullName = `${this.firstName} ${this.lastName}`;
}
}5. 總結(jié)
Vue 的 computed 屬性通過(guò)依賴追蹤和緩存策略,實(shí)現(xiàn)了響應(yīng)式計(jì)算和性能優(yōu)化。
在實(shí)現(xiàn)原理上,computed 屬性依賴于 Vue 的響應(yīng)式系統(tǒng),通過(guò) Watcher 實(shí)例進(jìn)行依賴收集和緩存控制。
通過(guò)深入理解和掌握 computed 屬性的實(shí)現(xiàn)原理,開(kāi)發(fā)者可以更好地利用這一特性,提高應(yīng)用的性能和可維護(hù)性。
在實(shí)際開(kāi)發(fā)中,應(yīng)根據(jù)具體需求合理使用 computed 屬性,并結(jié)合其他優(yōu)化手段,如避免不必要的計(jì)算和使用 Watcher 進(jìn)行細(xì)粒度控制,從而構(gòu)建高效、穩(wěn)定的 Vue 應(yīng)用。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue實(shí)現(xiàn)excel文件導(dǎo)入導(dǎo)出操作示例
這篇文章主要為大家介紹了vue實(shí)現(xiàn)excel文件的導(dǎo)入導(dǎo)出實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
Vue使用vue-cli創(chuàng)建項(xiàng)目
這篇文章主要介紹了Vue使用vue-cli創(chuàng)建項(xiàng)目,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09
vue el-form-item如何添加icon和tooltip
這篇文章主要介紹了vue el-form-item如何添加icon和tooltip問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10
Vue.js中實(shí)現(xiàn)密碼修改及頁(yè)面跳轉(zhuǎn)和刷新的完整指南
在現(xiàn)代Web應(yīng)用中,用戶賬戶管理是一個(gè)核心功能,其中密碼修改是一個(gè)常見(jiàn)的需求,本文將詳細(xì)介紹如何在Vue.js應(yīng)用中實(shí)現(xiàn)用戶密碼修改功能,并在成功后跳轉(zhuǎn)到登錄頁(yè)面并刷新該頁(yè)面,需要的朋友可以參考下2024-12-12
element-ui Upload上傳組件動(dòng)態(tài)配置action方式
這篇文章主要介紹了element-ui Upload上傳組件動(dòng)態(tài)配置action方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
vue.js實(shí)現(xiàn)數(shù)據(jù)庫(kù)的JSON數(shù)據(jù)輸出渲染到html頁(yè)面功能示例
這篇文章主要介紹了vue.js實(shí)現(xiàn)數(shù)據(jù)庫(kù)的JSON數(shù)據(jù)輸出渲染到html頁(yè)面功能,結(jié)合實(shí)例形式分析了vue.js針對(duì)本地json數(shù)據(jù)的讀取、遍歷輸出相關(guān)操作技巧,需要的朋友可以參考下2019-08-08
Vue項(xiàng)目在IE瀏覽器頁(yè)面白屏且報(bào)錯(cuò)SCRIPT1010:缺少標(biāo)識(shí)符問(wèn)題
Vue項(xiàng)目在谷歌瀏覽器中正常運(yùn)行,但在IE瀏覽器中出現(xiàn)問(wèn)題,如白屏和控制臺(tái)報(bào)錯(cuò),解決過(guò)程包括檢查IE設(shè)置、調(diào)整編輯器配置、引入兼容性插件、使用productionSourceMap定位錯(cuò)誤、檢查插件依賴和版本,以及重新構(gòu)建項(xiàng)目2024-09-09
Vue結(jié)合原生js實(shí)現(xiàn)自定義組件自動(dòng)生成示例
這篇文章主要介紹了Vue結(jié)合原生js實(shí)現(xiàn)自定義組件自動(dòng)生成示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01

