vue面試常考之computed是如何實(shí)現(xiàn)的
前言
通過(guò)前面幾篇文章,我們對(duì)Vue3中的響應(yīng)式設(shè)計(jì)有了初步的了解。
- 面試官:Vue3響應(yīng)式系統(tǒng)都不會(huì)寫(xiě),還敢說(shuō)精通?
- 面試官:你覺(jué)得Vue的響應(yīng)式系統(tǒng)僅僅是一個(gè)Proxy?
- Vue3:原來(lái)你是這樣的“異步更新”
而對(duì)于每天都在用的計(jì)算屬性(computed),我猜你肯定也想窺探其奧妙與原理對(duì)吧!走起!??!
從computed的特性出發(fā)
computed最耀眼的幾個(gè)特性是啥?
1. 依賴追蹤
import?{?reactive,?computed?}?from?'vue'
const?state?=?reactive({
??a:?1,
??b:?2,
??c:?3,
})
const?sum?=?computed(()?=>?{
??return?state.a?+?state.b
})我們定義了一個(gè)響應(yīng)式數(shù)據(jù)state和一個(gè)計(jì)算屬性sum, Vue會(huì)自動(dòng)追蹤sum依賴的數(shù)據(jù)state.a和state.b,并建立相應(yīng)的依賴關(guān)系。
也就是只有state.a和state.b發(fā)生變化的時(shí)候,sum才會(huì)重新計(jì)算而state.c任由它怎么變,sum都將絲毫不受影響。
2. 緩存
還是上面的例子,如果state.a和state.b打死都不再改變值了,那么我們讀取sum的時(shí)候,它將會(huì)返回上一次計(jì)算的結(jié)果,而不是重新計(jì)算。
3. 懶計(jì)算
這個(gè)特性比較容易被忽略,簡(jiǎn)單地說(shuō)只有計(jì)算屬性真正被使用(讀取)的時(shí)候才會(huì)進(jìn)行計(jì)算,否則咱就僅僅是定義了一個(gè)變量而已。
import?{?reactive,?computed?}?from?'vue'
const?state?=?reactive({
??a:?1,
??b:?2,
??c:?3
})
const?sum?=?computed(()?=>?{
??console.log('執(zhí)行計(jì)算')
??return?state.a?+?state.b
})
setTimeout(()?=>?{
??//?沒(méi)有讀取sum.value之前,sum不會(huì)進(jìn)行計(jì)算
??console.log('1-sum',?sum.value)
??//?我們改變了a的值,但是sum并不會(huì)立刻進(jìn)行計(jì)算
??state.a?=?4
??setTimeout(()?=>?{
????//?而是要等到再次讀取的時(shí)候才會(huì)觸發(fā)重新計(jì)算
????console.log('2-sum',?sum.value)
??},?1000)
},?1000)
挨個(gè)實(shí)現(xiàn)computed特性
1. 懶計(jì)算
我們依舊圍繞effect函數(shù)來(lái)搞事情,到目前為止,effect注冊(cè)的回調(diào)都是立刻執(zhí)行。
const?state?=?reactive({
??a:?1,
??b:?2,
??c:?3
})
//?有沒(méi)有很像計(jì)算屬性的感覺(jué)
const?sum?=?effect(()?=>?{
??console.log('執(zhí)行計(jì)算')?//?立刻被打印
??const?value?=?state.a?+?state.b
??return?value
})
console.log(sum)?//?undefined想要實(shí)現(xiàn)computed的懶執(zhí)行,咱們可以參考上篇文章Vue3:原來(lái)你是這樣的“異步更新”的思路,添加一個(gè)額外的參數(shù)lazy。
它要實(shí)現(xiàn)的功能是:如果傳遞了lazy為true,副作用函數(shù)將不會(huì)立即執(zhí)行,而是將執(zhí)行的時(shí)機(jī)交還給用戶,由用戶決定啥時(shí)候執(zhí)行。
當(dāng)然啦!回調(diào)的結(jié)果我們也應(yīng)該一并返回(例如上面的value值)
你能想象,我們僅僅需要改造幾行代碼就能離computed近了一大步。
const?effect?=?function?(fn,?options?=?{})?{
??const?effectFn?=?()?=>?{
????//?...?省略
????//?新增res存儲(chǔ)fn執(zhí)行的結(jié)果
????const?res?=?fn()
????//?...?省略
????//?新增返回結(jié)果
????return?res
??}
??//?...?省略
??//?新增,只有l(wèi)azy不為true時(shí)才會(huì)立即執(zhí)行
??if?(!options.lazy)?{
????effectFn()
??}
??//?新增,返回副作用函數(shù)讓用戶執(zhí)行
??return?effectFn
}測(cè)試一波
const?state?=?reactive({
??a:?1,
??b:?2,
??c:?3,
});
//?有沒(méi)有很像計(jì)算屬性的感覺(jué)
const?sum?=?effect(()?=>?{
??console.log("執(zhí)行計(jì)算");?//?調(diào)用sum函數(shù)后被打印
??const?value?=?state.a?+?state.b;
??return?value;
},?{
??lazy:?true
});
//?不執(zhí)行sum函數(shù),effect注冊(cè)的回調(diào)將不會(huì)執(zhí)行
console.log(sum());?//?32. 依賴追蹤
咱們初步實(shí)現(xiàn)了懶執(zhí)行的特性,為了更像computed一點(diǎn),我們需要封裝一個(gè)函數(shù)。
function?computed?(getter)?{
??const?effectFn?=?effect(getter,?{
????lazy:?true,
??})
??const?obj?=?{
????get?value?()?{
??????return?effectFn()
????}
??}
??return?obj
}這就有點(diǎn)那么味道啦!
測(cè)試一波
可以看到computed只會(huì)依賴state.a和state.b,而不會(huì)依賴state.c,這得益于我們前面幾篇文章實(shí)現(xiàn)的響應(yīng)式系統(tǒng),所以到了計(jì)算屬性這里,我們不用改動(dòng)任何代碼,天然就支持。
不過(guò)還是有點(diǎn)小問(wèn)題,我們讀取了兩次sum.value,sum卻被執(zhí)行了兩次,這和computed緩存的特性就不符了。
別急,馬上就要實(shí)現(xiàn)了這個(gè)最重要的特性了。
const?state?=?reactive({
??a:?1,
??b:?2,
??c:?3
})
const?sum?=?computed(()?=>?{
??console.log('執(zhí)行計(jì)算')
??return?state.a?+?state.b
})
console.log(sum.value)
console.log(sum.value)
3. 緩存
回顧一下computed的緩存特性:
- 只有當(dāng)其依賴的東西發(fā)生變化了才需要重新計(jì)算
- 否則就返回上一次執(zhí)行的結(jié)果。
為了緩存上一次計(jì)算的結(jié)果,咱們需要定義一個(gè)value變量,現(xiàn)在的關(guān)鍵是怎么才能知道其依賴的數(shù)據(jù)發(fā)生變化了呢?
function?computed?(getter)?{
??const?effectFn?=?effect(getter,?{
????lazy:?true,
??})
??let?value
??let?dirty?=?true
??const?obj?=?{
????get?value?()?{
??????//?2.?只有數(shù)據(jù)發(fā)生變化了才去重新計(jì)算
??????if?(dirty)?{
????????value?=?effectFn()
????????dirty?=?false
??????}
??????return?value
????}
??}
??return?obj
}測(cè)試一波
const?state?=?reactive({
??a:?1,
??b:?2,
??c:?3
})
const?sum?=?computed(()?=>?{
??console.log('執(zhí)行計(jì)算')
??return?state.a?+?state.b
})
console.log(sum.value)?//?3
console.log(sum.value)?//?3
state.a?=?4
console.log(sum.value)?//?3?答案是錯(cuò)誤的寄上任務(wù)調(diào)度
不得不說(shuō),任務(wù)調(diào)度實(shí)在太強(qiáng)大了,不僅僅可以實(shí)現(xiàn)數(shù)組的異步批量更新、在computed和watch中也是必不可少的。
function?computed?(getter)?{
??const?effectFn?=?effect(getter,?{
????lazy:?true,
????//?數(shù)據(jù)發(fā)生變化后,不執(zhí)行注冊(cè)的回調(diào),而是執(zhí)行scheduler
????scheduler?()?{
??????//?數(shù)據(jù)發(fā)生了變化后,則重新設(shè)置為dirty,那么下次就會(huì)重新計(jì)算
??????dirty?=?true
????}
??})
??let?value
??let?dirty?=?true
??const?obj?=?{
????get?value?()?{
??????//?2.?只有數(shù)據(jù)發(fā)生變化了才去重新計(jì)算
??????if?(dirty)?{
????????value?=?effectFn()
????????dirty?=?false
??????}
??????return?value
????}
??}
??return?obj
}測(cè)試一波
const?state?=?reactive({
??a:?1,
??b:?2,
??c:?3
})
const?sum?=?computed(()?=>?{
??console.log('執(zhí)行計(jì)算')
??return?state.a?+?state.b
})
console.log(sum.value)?//?3
console.log(sum.value)?//?3
state.a?=?4
console.log(sum.value)?//?3?答案是錯(cuò)誤的完美?。?!這下面試官再也難不倒我了!??!

到此這篇關(guān)于vue面試常考之computed是如何實(shí)現(xiàn)的的文章就介紹到這了,更多相關(guān)vue computed內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue中解決拖拽改變存在iframe的div大小時(shí)卡頓問(wèn)題
這篇文章主要介紹了vue中解決拖拽改變存在iframe的div大小時(shí)卡頓問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
vue中iframe使用以及結(jié)合postMessage實(shí)現(xiàn)跨域通信
這篇文章主要介紹了vue中iframe使用以及結(jié)合postMessage實(shí)現(xiàn)跨域通信方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
el-form表單驗(yàn)證的一些實(shí)用方法總結(jié)
表單校驗(yàn)是注冊(cè)環(huán)節(jié)中必不可少的操作,表單校驗(yàn)通過(guò)一定的規(guī)則來(lái)確保用戶提交數(shù)據(jù)的有效性,下面這篇文章主要給大家介紹了關(guān)于el-form表單驗(yàn)證的一些實(shí)用方法,需要的朋友可以參考下2023-01-01
vue單頁(yè)應(yīng)用中如何使用jquery的方法示例
最近在工作中遇到的一個(gè)需求,需要在vue-cli建立的應(yīng)用中引入jquery的方式,通過(guò)查找相關(guān)的資料最終解決了,所以這篇文章主要給大家介紹了關(guān)于在vue單頁(yè)應(yīng)用中如何使用jquery的方法示例,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-07-07
element plus el-table多選框跨頁(yè)多選保留功能
這篇文章主要介紹了element plus el-table多選框跨頁(yè)多選保留功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2025-05-05
vite+vue3項(xiàng)目啟動(dòng)報(bào)錯(cuò)Unexpected?“%“問(wèn)題及解決
這篇文章主要介紹了vite+vue3項(xiàng)目啟動(dòng)報(bào)錯(cuò)Unexpected?“%“問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
vue+iview+less+echarts實(shí)戰(zhàn)項(xiàng)目總結(jié)
本篇文章是作者通過(guò)學(xué)習(xí)vue+iview+less+echarts制作一個(gè)小系統(tǒng)后,做的心得以及遇到的坑的總結(jié),值得大家學(xué)習(xí)參考。2018-02-02

