Vue中的Computed實現(xiàn)原理分析
在 Vue.js 中,computed 屬性是一種強(qiáng)大的特性,用于定義依賴于其他響應(yīng)式數(shù)據(jù)的計算值。
computed 屬性不僅能夠簡化模板中的表達(dá)式,還能夠緩存計算結(jié)果,避免不必要的重復(fù)計算,從而提高性能。
將深入探討 Vue 中 computed 屬性的實現(xiàn)原理,包括其工作機(jī)制、依賴追蹤、緩存策略等方面。
1. Computed 屬性概述
Computed 屬性是 Vue 實例中的一個特殊屬性,它允許開發(fā)者定義一個計算值,該值依賴于其他響應(yīng)式數(shù)據(jù)。
Computed 屬性具有以下特點:
- 響應(yīng)式:當(dāng)依賴的數(shù)據(jù)發(fā)生變化時,computed 屬性會自動重新計算。
- 緩存:computed 屬性會緩存計算結(jié)果,只有當(dāng)依賴的數(shù)據(jù)發(fā)生變化時,才會重新計算。
- 惰性求值:computed 屬性在首次訪問時才會進(jìn)行計算,之后會根據(jù)依賴數(shù)據(jù)的變化情況決定是否重新計算。
2. Computed 屬性的基本用法
在 Vue 實例中,可以通過 computed
選項來定義 computed 屬性。
new Vue({ data() { return { firstName: 'John', lastName: 'Doe' }; }, computed: { fullName() { return `${this.firstName} ${this.lastName}`; } } });
在上述代碼中,fullName
是一個 computed 屬性,它依賴于 firstName
和 lastName
。
當(dāng) firstName
或 lastName
發(fā)生變化時,fullName
會自動重新計算。
3. Computed 屬性的實現(xiàn)原理
3.1 依賴追蹤
Vue 的 computed 屬性實現(xiàn)依賴于 Vue 的響應(yīng)式系統(tǒng)。
Vue 通過 Object.defineProperty
或 Proxy
來劫持?jǐn)?shù)據(jù)的變化,并在數(shù)據(jù)變化時通知依賴該數(shù)據(jù)的觀察者。
3.1.1 響應(yīng)式數(shù)據(jù)劫持
Vue 在初始化數(shù)據(jù)時,會通過 Object.defineProperty
或 Proxy
對數(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ù)通過 Object.defineProperty
劫持了對象的屬性,并在 get
和 set
方法中分別收集和通知依賴。
3.1.2 依賴收集
在 computed 屬性被訪問時,Vue 會通過 Dep.target
來收集依賴。
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
實例在 get
方法中將自身設(shè)置為 Dep.target
,然后訪問 computed 屬性,從而觸發(fā)依賴數(shù)據(jù)的 get
方法,完成依賴收集。
3.2 緩存策略
Computed 屬性具有緩存機(jī)制,只有在依賴數(shù)據(jù)發(fā)生變化時,才會重新計算。
3.2.1 緩存實現(xiàn)
Vue 通過 Watcher
實例的 dirty
屬性來控制緩存。
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
實例的 dirty
屬性用于標(biāo)記 computed 屬性是否需要重新計算。
當(dāng)依賴數(shù)據(jù)發(fā)生變化時,Watcher
的 update
方法會將 dirty
設(shè)置為 true
,表示需要重新計算。
3.2.2 惰性求值
Computed 屬性在首次訪問時才會進(jìn)行計算,之后會根據(jù) dirty
屬性決定是否重新計算。
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ù)返回一個 computed 屬性的 getter 函數(shù)。
在訪問 computed 屬性時,如果 dirty
為 true
,則會調(diào)用 watcher.evaluate
方法進(jìn)行計算,并將 dirty
設(shè)置為 false
,表示計算結(jié)果已緩存。
4. Computed 屬性的優(yōu)化
4.1 避免不必要的計算
在定義 computed 屬性時,應(yīng)盡量避免不必要的計算。
例如,如果 computed 屬性的計算邏輯較為復(fù)雜,可以考慮將其拆分為多個簡單的 computed 屬性。
computed: { fullName() { return `${this.firstName} ${this.lastName}`; }, formattedName() { return this.fullName.toUpperCase(); } }
4.2 使用 Watcher 進(jìn)行性能優(yōu)化
在某些情況下,可以使用 watch
選項來替代 computed 屬性,以實現(xiàn)更細(xì)粒度的控制和性能優(yōu)化。
watch: { firstName: 'updateFullName', lastName: 'updateFullName' }, methods: { updateFullName() { this.fullName = `${this.firstName} ${this.lastName}`; } }
5. 總結(jié)
Vue 的 computed 屬性通過依賴追蹤和緩存策略,實現(xiàn)了響應(yīng)式計算和性能優(yōu)化。
在實現(xiàn)原理上,computed 屬性依賴于 Vue 的響應(yīng)式系統(tǒng),通過 Watcher
實例進(jìn)行依賴收集和緩存控制。
通過深入理解和掌握 computed 屬性的實現(xiàn)原理,開發(fā)者可以更好地利用這一特性,提高應(yīng)用的性能和可維護(hù)性。
在實際開發(fā)中,應(yīng)根據(jù)具體需求合理使用 computed 屬性,并結(jié)合其他優(yōu)化手段,如避免不必要的計算和使用 Watcher 進(jìn)行細(xì)粒度控制,從而構(gòu)建高效、穩(wěn)定的 Vue 應(yīng)用。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決Vue3.0刷新頁面警告[Vue Router warn]:No match 
這篇文章主要介紹了解決Vue3.0刷新頁面警告[Vue Router warn]:No match found for location with path /xxx問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03vue2文件流下載成功后文件格式錯誤、打不開及內(nèi)容缺失的解決方法
使用Vue時我們前端如何處理后端返回的文件流,下面這篇文章主要給大家介紹了關(guān)于vue2文件流下載成功后文件格式錯誤、打不開及內(nèi)容缺失的解決方法,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04實現(xiàn)vuex與組件data之間的數(shù)據(jù)同步更新方式
今天小編就為大家分享一篇實現(xiàn)vuex與組件data之間的數(shù)據(jù)同步更新方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11vue實現(xiàn)element上傳多張圖片瀏覽刪除功能
這篇文章主要介紹了vue實現(xiàn)element上傳多張圖片瀏覽刪除功能,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-10-10vue webpack開發(fā)訪問后臺接口全局配置的方法
今天小編就為大家分享一篇vue webpack開發(fā)訪問后臺接口全局配置的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09