Vue3實(shí)現(xiàn)計(jì)算屬性的代碼詳解
代碼解釋
import { ReactiveEffect } from "./effect"
class computedImpl {
private _fn: any
private stop: boolean = true
private _value: any
private _effect: any
constructor(fn) {
this._fn = fn // (1)
this._effect = new ReactiveEffect(fn, () => { // (2)
if (!this.stop) {
this.stop = true
}
})
}
get value() {
if(this.stop) {
this.stop = false
this._value = this._effect.run()
}
return this._value
}
}
export function computed(fn) {
return new computedImpl(fn)
}可以看到代碼其實(shí)很簡(jiǎn)單,創(chuàng)建了一個(gè)computedImpl類(lèi),這個(gè)類(lèi)接收一個(gè)函數(shù)作為其參數(shù),最下面將實(shí)例化的computedImpl對(duì)象拋出即可。
看著很簡(jiǎn)單,那我們來(lái)介紹下計(jì)算屬性在這個(gè)類(lèi)里面做了什么?
一、實(shí)例化的時(shí)候會(huì)將傳進(jìn)去函數(shù)緩存起來(lái)(1)
二、創(chuàng)建一個(gè)ReactiveEffect對(duì)象,將傳入的fn作為參數(shù)傳入,第二個(gè)參數(shù)處接收一個(gè)scheduler函數(shù)(2)
() => {
if (!this.stop) {
this.stop = true
}
}這里介紹一下這一步的作用:
Vue3 有一個(gè)ReactiveEffect這樣的類(lèi),接收兩個(gè)參數(shù),一個(gè)是默認(rèn)函數(shù),另一個(gè)是scheduler函數(shù)。
創(chuàng)建這樣的類(lèi)有什么作用呢?首先我們知道傳入的函數(shù)里面肯定有響應(yīng)式的數(shù)據(jù),因?yàn)橛?jì)算屬性的作用是當(dāng)響應(yīng)式數(shù)據(jù)更新時(shí)重新計(jì)算我們傳入的計(jì)算屬性函數(shù)。,意味著我們要給給這些響應(yīng)式數(shù)據(jù)去收集一個(gè)依賴(lài),用于告訴我們計(jì)算屬性響應(yīng)式數(shù)據(jù)是否有發(fā)生變動(dòng)。
那我們Vue3是怎么去收集依賴(lài)的呢?那就不得不提到ReactiveEffect了,實(shí)例化ReactiveEffect對(duì)象有一個(gè)run函數(shù),當(dāng)我們執(zhí)行run函數(shù)的時(shí)候會(huì)執(zhí)行一遍我們傳入的fn并且將自身指向一個(gè)全局變量activeEffect,當(dāng)我們響應(yīng)式數(shù)據(jù)發(fā)生取值操作的時(shí)候就會(huì)去收集依賴(lài),就是去判斷activeEffect是否存在,如果存在收集起來(lái)。
當(dāng)響應(yīng)式數(shù)據(jù)發(fā)生set操作的時(shí)候,就會(huì)去觸發(fā)依賴(lài),那么我們之前存進(jìn)去的實(shí)例化ReactiveEffect對(duì)象就會(huì)被拿出來(lái)執(zhí)行,這樣我們就可以知道數(shù)據(jù)發(fā)生了改變,默認(rèn)情況下會(huì)執(zhí)行ReactiveEffect傳進(jìn)的默認(rèn)函數(shù),但是如果scheduler函數(shù)存在那就會(huì)執(zhí)行scheduler函數(shù)。
三、計(jì)算屬性函數(shù)執(zhí)行與緩存
上面已經(jīng)知道如何實(shí)現(xiàn)依賴(lài)收集的了,那么講解下函數(shù)執(zhí)行和緩存的實(shí)現(xiàn)。
因?yàn)?code>我們已經(jīng)創(chuàng)建了一個(gè)實(shí)例化ReactiveEffect對(duì)象,在執(zhí)行這個(gè)對(duì)象的run函數(shù)時(shí)會(huì)執(zhí)行我們傳入的函數(shù),所以當(dāng)我們get Value的時(shí)候就會(huì)執(zhí)行一遍函數(shù),因?yàn)閳?zhí)行函數(shù)的時(shí)候會(huì),觸發(fā)響應(yīng)式對(duì)象的取值操作,ReactiveEffect對(duì)象被存儲(chǔ)到依賴(lài)中,并且返回函數(shù)的計(jì)算結(jié)果。
這樣我們每次執(zhí)行g(shù)et Value都會(huì)執(zhí)行函數(shù)拿到函數(shù)結(jié)果。因?yàn)閏omputed會(huì)有緩存功能,所以這里又設(shè)置了一個(gè)_value和stop用在結(jié)果緩存和開(kāi)關(guān),默認(rèn)get Value操作走一遍stop的判斷函數(shù)執(zhí)行完之后關(guān)閉開(kāi)關(guān),防止每次執(zhí)行都會(huì)走一遍函數(shù),然后將函數(shù)結(jié)果緩存到_value中,下次直接拿_value就行
if(this.stop) {
this.stop = false
this._value = this._effect.run()
}
return this._value上面的代碼可以看到我們這個(gè)開(kāi)關(guān)一關(guān)閉就不會(huì)打開(kāi)了,那我們豈不是每次都會(huì)拿到老的值?
回到上面的實(shí)例化ReactiveEffect對(duì)象中,這里傳入了一個(gè)scheduler函數(shù)。
() => {
if (!this.stop) {
this.stop = true
}
}當(dāng)響應(yīng)式數(shù)據(jù)發(fā)生改變的時(shí)候scheduler函數(shù)執(zhí)行,stop開(kāi)關(guān)打開(kāi),那我們下一次執(zhí)行g(shù)et Value就會(huì)重新執(zhí)行函數(shù)更新計(jì)算屬性的結(jié)果
總結(jié)
在computed實(shí)際上是返回了一個(gè)實(shí)例化的對(duì)象,這個(gè)對(duì)象在實(shí)例化的時(shí)候接收了一個(gè)參數(shù)就是computed內(nèi)部的回調(diào)。
因?yàn)閏omputed是緩存的,所以返回的實(shí)例化對(duì)象中有一個(gè)get方法,取值的時(shí)候就會(huì)將傳入的回調(diào)給執(zhí)行了,并且把結(jié)果設(shè)置為實(shí)例化對(duì)象的內(nèi)部屬性,并返回出去。
所以computed在取值的時(shí)候?qū)嶋H上就讀取了存在在對(duì)象中的回調(diào)函數(shù)的執(zhí)行結(jié)果。
因?yàn)閏omputed會(huì)緩存所以在執(zhí)行g(shù)et方法的時(shí)候會(huì)做一個(gè)開(kāi)關(guān),比如說(shuō)lazy默認(rèn)為true,只有當(dāng)lazy為true才能執(zhí)行回調(diào)函數(shù),當(dāng)函數(shù)執(zhí)行完lazy改成false,所以后續(xù)的取值操作都不執(zhí)行函數(shù),實(shí)現(xiàn)了緩存的功能。
因?yàn)槿绻鹀omputed里面的響應(yīng)式對(duì)象如果發(fā)生了改變,computed的結(jié)果是需要更新的,所以需要對(duì)computed里面的響應(yīng)式對(duì)象進(jìn)行一個(gè)依賴(lài)設(shè)置。
vue在進(jìn)行依賴(lài)收集的時(shí)候會(huì)用一個(gè)全局的變量去存儲(chǔ)回調(diào)函數(shù),在響應(yīng)式對(duì)象get操作的時(shí)候就會(huì)判斷這個(gè)全局變量是否存在,如果存在則加到依賴(lài)中,后續(xù)set操作的時(shí)候就拿這些存儲(chǔ)的依賴(lài)處理執(zhí)行。
所以computed在實(shí)例化對(duì)象的時(shí)候,會(huì)構(gòu)造一個(gè)這樣一個(gè)全局變量然后里面的回調(diào)函數(shù)的作用是如果執(zhí)行l(wèi)azy置為true,即開(kāi)關(guān)打開(kāi)。
然后因?yàn)槿ト≈档臅r(shí)候會(huì)執(zhí)行一次函數(shù),所以響應(yīng)式對(duì)象get被觸發(fā),把lazy置為true的回調(diào)存入依賴(lài)中,下次響應(yīng)式對(duì)象更新值即set的時(shí)候,computed返回的實(shí)例對(duì)象內(nèi)部的開(kāi)關(guān)就會(huì)被打開(kāi)了。
所以我們下一次執(zhí)行computed的value的時(shí)候,因?yàn)殚_(kāi)關(guān)是開(kāi)的所以會(huì)重新執(zhí)行一遍函數(shù)并更新實(shí)例化對(duì)象的值,然后開(kāi)關(guān)關(guān)上緩存起來(lái),返回新的值。
以上就是Vue3實(shí)現(xiàn)計(jì)算屬性的代碼詳解的詳細(xì)內(nèi)容,更多關(guān)于Vue3計(jì)算屬性的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue項(xiàng)目報(bào)錯(cuò):Missing?script:"serve"的解決辦法
這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目報(bào)錯(cuò):Missing?script:"serve"的解決辦法,"missing script: serve"是一個(gè)錯(cuò)誤信息,意味著在執(zhí)行啟動(dòng)腳本時(shí),找不到名為"serve"的腳本,需要的朋友可以參考下2023-11-11
Vue使用Props實(shí)現(xiàn)組件數(shù)據(jù)交互的示例代碼
在Vue中,組件的props屬性用于定義組件可以接收的外部數(shù)據(jù),這些數(shù)據(jù)來(lái)自父組件并傳遞給子組件,本文給大家介紹了Vue使用Props實(shí)現(xiàn)組件數(shù)據(jù)交互,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下2024-06-06
Vue3+vuedraggable實(shí)現(xiàn)動(dòng)態(tài)配置頁(yè)面
這篇文章主要為大家詳細(xì)介紹了Vue3如何利用vuedraggable實(shí)現(xiàn)動(dòng)態(tài)配置頁(yè)面,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2023-12-12
Vue3 封裝 element-plus 圖標(biāo)選擇器實(shí)現(xiàn)步驟
這篇文章主要介紹了Vue3 封裝 element-plus 圖標(biāo)選擇器,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09
vue3.0安裝element?plus依賴(lài)的過(guò)程
這篇文章主要介紹了vue3.0安裝element?plus依賴(lài)的過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-04-04
Vue-element中el-input輸入卡頓問(wèn)題的解決
這篇文章主要介紹了Vue-element中el-input輸入卡頓問(wèn)題的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
vue的v-if里實(shí)現(xiàn)調(diào)用函數(shù)
這篇文章主要介紹了vue的v-if里實(shí)現(xiàn)調(diào)用函數(shù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07

