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è)特殊屬性,它允許開發(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 屬性在首次訪問時(shí)才會(huì)進(jìn)行計(jì)算,之后會(huì)根據(jù)依賴數(shù)據(jù)的變化情況決定是否重新計(jì)算。
2. Computed 屬性的基本用法
在 Vue 實(shí)例中,可以通過 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 通過 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ì)通過 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ù)通過 Object.defineProperty
劫持了對(duì)象的屬性,并在 get
和 set
方法中分別收集和通知依賴。
3.1.2 依賴收集
在 computed 屬性被訪問時(shí),Vue 會(huì)通過 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
,然后訪問 computed 屬性,從而觸發(fā)依賴數(shù)據(jù)的 get
方法,完成依賴收集。
3.2 緩存策略
Computed 屬性具有緩存機(jī)制,只有在依賴數(shù)據(jù)發(fā)生變化時(shí),才會(huì)重新計(jì)算。
3.2.1 緩存實(shí)現(xiàn)
Vue 通過 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 屬性在首次訪問時(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ù)。
在訪問 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 屬性通過依賴追蹤和緩存策略,實(shí)現(xiàn)了響應(yīng)式計(jì)算和性能優(yōu)化。
在實(shí)現(xiàn)原理上,computed 屬性依賴于 Vue 的響應(yīng)式系統(tǒng),通過 Watcher
實(shí)例進(jìn)行依賴收集和緩存控制。
通過深入理解和掌握 computed 屬性的實(shí)現(xiàn)原理,開發(fā)者可以更好地利用這一特性,提高應(yīng)用的性能和可維護(hù)性。
在實(shí)際開發(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)文章
解決Vue3.0刷新頁(yè)面警告[Vue Router warn]:No match 
這篇文章主要介紹了解決Vue3.0刷新頁(yè)面警告[Vue Router warn]:No match found for location with path /xxx問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03vue2文件流下載成功后文件格式錯(cuò)誤、打不開及內(nèi)容缺失的解決方法
使用Vue時(shí)我們前端如何處理后端返回的文件流,下面這篇文章主要給大家介紹了關(guān)于vue2文件流下載成功后文件格式錯(cuò)誤、打不開及內(nèi)容缺失的解決方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04Vue 多層組件嵌套二種實(shí)現(xiàn)方式(測(cè)試實(shí)例)
本篇文章主要介紹了Vue組件嵌套二種實(shí)現(xiàn)方式(測(cè)試實(shí)例),具有一定的參考價(jià)值,代碼很簡(jiǎn)單,感興趣的小伙伴們可以參考一下2017-09-09實(shí)現(xiàn)vuex與組件data之間的數(shù)據(jù)同步更新方式
今天小編就為大家分享一篇實(shí)現(xiàn)vuex與組件data之間的數(shù)據(jù)同步更新方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2019-11-11vue實(shí)現(xiàn)element上傳多張圖片瀏覽刪除功能
這篇文章主要介紹了vue實(shí)現(xiàn)element上傳多張圖片瀏覽刪除功能,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-10-10vue webpack開發(fā)訪問后臺(tái)接口全局配置的方法
今天小編就為大家分享一篇vue webpack開發(fā)訪問后臺(tái)接口全局配置的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2018-09-09