詳解Vue計(jì)算屬性原理
初始化
組件初始化時(shí)會(huì)調(diào)用掛載在Vue原型鏈上的_init
方法,即Vue.prototype._init
:
function Vue(options) { this._init(options) }
同時(shí)_init
方法會(huì)調(diào)用initState
方法,這個(gè)方法主要用來初始化props、methods、data、watch以及本文所介紹的computed:
Vue.prototype._init = function (options?: Record<string, any>) { // ...省略一些代碼 initState(vm) // ...省略一些代碼 }
為了看上去一目了然,這里省略了一些代碼(包括判斷條件)
export function initState(vm: Component) { // ..省略了一些代碼 initProps(vm, opts.props) initMethods(vm, opts.methods) initData(vm) initComputed(vm, opts.computed) initWatch(vm, opts.watch) }
走到這里之后,程序就進(jìn)入了初始化計(jì)算屬性的過程中
initComputed
在這個(gè)方法里,主要做了兩件事:
- 遍歷用戶傳入的計(jì)算屬性,生成相應(yīng)的
Wacher
,每個(gè)Watcher
都被標(biāo)記為lazy
- 在組件實(shí)例
vm
上掛載同名屬性,值為一個(gè)按條件生成的getter
函數(shù)
以下代碼有省略
function initComputed(vm: Component, computed: Object) { const watchers = (vm._computedWatchers = Object.create(null)) for (const key in computed) { const userDef = computed[key]; // 獲取用戶自定義的計(jì)算屬性getter const getter = isFunction(userDef) ? userDef : userDef.get; watchers[key] = new Watcher( vm, getter || noop, noop, { lazy: true } ); defineComputed(vm, key, userDef); } }
其中new Watcher
會(huì)生成Watcher
實(shí)例:
export default class Watcher implements DepTarget { constructor( vm: Component | null, expOrFn: string | (() => any), cb: Function, options?: WatcherOptions | null, isRenderWatcher?: boolean ) { this.getter = expOrFn this.value = this.lazy ? undefined : this.get(); }
因?yàn)槲覀儌魅氲?code>lazy配置,Wacher不會(huì)執(zhí)行Watcher.prototype.get()
方法,這個(gè)方法主要用于依賴收集
defineComputed
這個(gè)方法主要是在組件實(shí)例上生成相應(yīng)的計(jì)算屬性,便于我們?cè)诮M件內(nèi)部通過this[key]
的方式進(jìn)行獲取,主要代碼如下:
export function defineComputed( target: any, key: string, userDef: Record<string, any> | (() => any) ) { sharedPropertyDefinition.get = createComputedGetter(key); Object.defineProperty(target, key, sharedPropertyDefinition) }
這里的target
就是組件實(shí)例,key
即為我們定義的相應(yīng)的響應(yīng)式屬性名,它的值是一個(gè) 生成的getter
;
createComputedGetter
有了訪問屬性的方式,那么就需要返回相應(yīng)的計(jì)算屬性值,這個(gè)方法主要用來實(shí)現(xiàn)計(jì)算屬性的惰性求值的:
function createComputedGetter(key) { return function computedGetter() { const watcher = this._computedWatchers && this._computedWatchers[key] if (watcher) { if (watcher.dirty) { watcher.evaluate() } // ... return watcher.value } } }
這里返回的函數(shù)就是用于設(shè)置Object.defineProperty
的getter的存取描述符get
,它會(huì)根據(jù)watcher.dirty
,判斷是否需要調(diào)用方法watcher.evaluate()
進(jìn)行求值。 在watcher.evaluate
方法里主要做兩件事:
- 調(diào)用
get
方法進(jìn)行依賴收集(會(huì)調(diào)用我們?cè)谟?jì)算屬性上定義的函數(shù),從而觸發(fā)相應(yīng)的響應(yīng)式數(shù)據(jù)的getter進(jìn)行依賴收集) - 將
watcher
的dirty
標(biāo)志位置為false
this.value = this.get() this.dirty = false
完成了上述步驟后,整個(gè)響應(yīng)式屬性就建立完畢,當(dāng)計(jì)算屬性依賴的數(shù)據(jù)發(fā)生變化時(shí),會(huì)調(diào)用watcher.update()
方法,這個(gè)方法會(huì)再次將dirty
標(biāo)志位寫為false
。當(dāng)我們?cè)谀0胬锘蚱渌胤皆L問組件實(shí)例上的響應(yīng)式屬性后,就會(huì)觸發(fā)上述定義的createComputedGetter
返回的函數(shù)。從而進(jìn)行wacher.evaluate()
求值進(jìn)行重新計(jì)算,計(jì)算完成后又將dirty
置為false
,等待下一次重新計(jì)算。如果我們不妨問這個(gè)屬性,那么是不會(huì)觸發(fā)getter,從而進(jìn)行計(jì)算的(惰性求值)。
總結(jié)
方法調(diào)用流程:
組件初始化 -> _init()
-> initState
-> initComputed
-> definedComputed
-> createComputedGetter
數(shù)據(jù)流:
watcher.evaluate
-> 依賴收集 -> dirty = false
-> update
-> dirty = true
-> 用戶訪問計(jì)算屬性 -> watcher.evaluate
-> 循環(huán)此過程...
紙上得來終覺淺 絕知此事要躬行
以上就是詳解Vue計(jì)算屬性原理的詳細(xì)內(nèi)容,更多關(guān)于Vue計(jì)算屬性原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue數(shù)據(jù)綁定簡(jiǎn)析小結(jié)
這篇文章主要介紹了Vue數(shù)據(jù)綁定簡(jiǎn)析小結(jié),本文將從源碼的角度來對(duì)Vue響應(yīng)式數(shù)據(jù)中的觀察者模式進(jìn)行簡(jiǎn)析。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-05-05Vue3+TypeScript實(shí)現(xiàn)二維碼生成組件
在?Web?應(yīng)用中,生成二維碼是常見的需求,本文介紹如何用?Vue3?和?TypeScript?開發(fā)一個(gè)二維碼生成組件,支持生成圖片或?canvas?形式的二維碼,并提供豐富的配置選項(xiàng),感興趣的小伙伴跟著小編一起來看看吧2024-04-04vue3.0公共組件自動(dòng)導(dǎo)入的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于vue3.0公共組件自動(dòng)導(dǎo)入的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04Vue代理報(bào)錯(cuò)404問題及解決(vue配置proxy)
這篇文章主要介紹了Vue代理報(bào)錯(cuò)404問題及解決(vue配置proxy),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12Vue3中axios請(qǐng)求封裝、請(qǐng)求攔截與相應(yīng)攔截詳解
目前前端最流行的網(wǎng)絡(luò)請(qǐng)求庫還是axios,所以對(duì)axios的封裝很有必要,下面這篇文章主要給大家介紹了關(guān)于Vue3中axios請(qǐng)求封裝、請(qǐng)求攔截與相應(yīng)攔截的相關(guān)資料,需要的朋友可以參考下2023-05-05vue發(fā)布到nginx下請(qǐng)求后臺(tái)404問題及解決
這篇文章主要介紹了vue發(fā)布到nginx下請(qǐng)求后臺(tái)404問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03