vue面試??贾甤omputed是如何實現(xiàn)的
前言
通過前面幾篇文章,我們對Vue3中的響應(yīng)式設(shè)計有了初步的了解。
而對于每天都在用的計算屬性(computed
),我猜你肯定也想窺探其奧妙與原理對吧!走起!??!
從computed的特性出發(fā)
computed
最耀眼的幾個特性是啥?
1. 依賴追蹤
import?{?reactive,?computed?}?from?'vue' const?state?=?reactive({ ??a:?1, ??b:?2, ??c:?3, }) const?sum?=?computed(()?=>?{ ??return?state.a?+?state.b })
我們定義了一個響應(yīng)式數(shù)據(jù)state
和一個計算屬性sum
, Vue會自動追蹤sum
依賴的數(shù)據(jù)state.a
和state.b
,并建立相應(yīng)的依賴關(guān)系。
也就是只有state.a
和state.b
發(fā)生變化的時候,sum
才會重新計算而state.c
任由它怎么變,sum
都將絲毫不受影響。
2. 緩存
還是上面的例子,如果state.a
和state.b
打死都不再改變值了,那么我們讀取sum
的時候,它將會返回上一次計算的結(jié)果,而不是重新計算。
3. 懶計算
這個特性比較容易被忽略,簡單地說只有計算屬性真正被使用(讀?。┑臅r候才會進(jìn)行計算,否則咱就僅僅是定義了一個變量而已。
import?{?reactive,?computed?}?from?'vue' const?state?=?reactive({ ??a:?1, ??b:?2, ??c:?3 }) const?sum?=?computed(()?=>?{ ??console.log('執(zhí)行計算') ??return?state.a?+?state.b }) setTimeout(()?=>?{ ??//?沒有讀取sum.value之前,sum不會進(jìn)行計算 ??console.log('1-sum',?sum.value) ??//?我們改變了a的值,但是sum并不會立刻進(jìn)行計算 ??state.a?=?4 ??setTimeout(()?=>?{ ????//?而是要等到再次讀取的時候才會觸發(fā)重新計算 ????console.log('2-sum',?sum.value) ??},?1000) },?1000)
挨個實現(xiàn)computed特性
1. 懶計算
我們依舊圍繞effect
函數(shù)來搞事情,到目前為止,effect
注冊的回調(diào)都是立刻執(zhí)行。
const?state?=?reactive({ ??a:?1, ??b:?2, ??c:?3 }) //?有沒有很像計算屬性的感覺 const?sum?=?effect(()?=>?{ ??console.log('執(zhí)行計算')?//?立刻被打印 ??const?value?=?state.a?+?state.b ??return?value }) console.log(sum)?//?undefined
想要實現(xiàn)computed
的懶執(zhí)行,咱們可以參考上篇文章Vue3:原來你是這樣的“異步更新”的思路,添加一個額外的參數(shù)lazy
。
它要實現(xiàn)的功能是:如果傳遞了lazy
為true
,副作用函數(shù)將不會立即執(zhí)行,而是將執(zhí)行的時機(jī)交還給用戶,由用戶決定啥時候執(zhí)行。
當(dāng)然啦!回調(diào)的結(jié)果我們也應(yīng)該一并返回(例如上面的value值)
你能想象,我們僅僅需要改造幾行代碼就能離computed
近了一大步。
const?effect?=?function?(fn,?options?=?{})?{ ??const?effectFn?=?()?=>?{ ????//?...?省略 ????//?新增res存儲fn執(zhí)行的結(jié)果 ????const?res?=?fn() ????//?...?省略 ????//?新增返回結(jié)果 ????return?res ??} ??//?...?省略 ??//?新增,只有l(wèi)azy不為true時才會立即執(zhí)行 ??if?(!options.lazy)?{ ????effectFn() ??} ??//?新增,返回副作用函數(shù)讓用戶執(zhí)行 ??return?effectFn }
測試一波
const?state?=?reactive({ ??a:?1, ??b:?2, ??c:?3, }); //?有沒有很像計算屬性的感覺 const?sum?=?effect(()?=>?{ ??console.log("執(zhí)行計算");?//?調(diào)用sum函數(shù)后被打印 ??const?value?=?state.a?+?state.b; ??return?value; },?{ ??lazy:?true }); //?不執(zhí)行sum函數(shù),effect注冊的回調(diào)將不會執(zhí)行 console.log(sum());?//?3
2. 依賴追蹤
咱們初步實現(xiàn)了懶執(zhí)行的特性,為了更像computed
一點,我們需要封裝一個函數(shù)。
function?computed?(getter)?{ ??const?effectFn?=?effect(getter,?{ ????lazy:?true, ??}) ??const?obj?=?{ ????get?value?()?{ ??????return?effectFn() ????} ??} ??return?obj }
這就有點那么味道啦!
測試一波
可以看到computed
只會依賴state.a
和state.b
,而不會依賴state.c
,這得益于我們前面幾篇文章實現(xiàn)的響應(yīng)式系統(tǒng),所以到了計算屬性這里,我們不用改動任何代碼,天然就支持。
不過還是有點小問題,我們讀取了兩次sum.value
,sum卻被執(zhí)行了兩次,這和computed
緩存的特性就不符了。
別急,馬上就要實現(xiàn)了這個最重要的特性了。
const?state?=?reactive({ ??a:?1, ??b:?2, ??c:?3 }) const?sum?=?computed(()?=>?{ ??console.log('執(zhí)行計算') ??return?state.a?+?state.b }) console.log(sum.value) console.log(sum.value)
3. 緩存
回顧一下computed
的緩存特性:
- 只有當(dāng)其依賴的東西發(fā)生變化了才需要重新計算
- 否則就返回上一次執(zhí)行的結(jié)果。
為了緩存上一次計算的結(jié)果,咱們需要定義一個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ā)生變化了才去重新計算 ??????if?(dirty)?{ ????????value?=?effectFn() ????????dirty?=?false ??????} ??????return?value ????} ??} ??return?obj }
測試一波
const?state?=?reactive({ ??a:?1, ??b:?2, ??c:?3 }) const?sum?=?computed(()?=>?{ ??console.log('執(zhí)行計算') ??return?state.a?+?state.b }) console.log(sum.value)?//?3 console.log(sum.value)?//?3 state.a?=?4 console.log(sum.value)?//?3?答案是錯誤的
寄上任務(wù)調(diào)度
不得不說,任務(wù)調(diào)度實在太強(qiáng)大了,不僅僅可以實現(xiàn)數(shù)組的異步批量更新、在computed
和watch
中也是必不可少的。
function?computed?(getter)?{ ??const?effectFn?=?effect(getter,?{ ????lazy:?true, ????//?數(shù)據(jù)發(fā)生變化后,不執(zhí)行注冊的回調(diào),而是執(zhí)行scheduler ????scheduler?()?{ ??????//?數(shù)據(jù)發(fā)生了變化后,則重新設(shè)置為dirty,那么下次就會重新計算 ??????dirty?=?true ????} ??}) ??let?value ??let?dirty?=?true ??const?obj?=?{ ????get?value?()?{ ??????//?2.?只有數(shù)據(jù)發(fā)生變化了才去重新計算 ??????if?(dirty)?{ ????????value?=?effectFn() ????????dirty?=?false ??????} ??????return?value ????} ??} ??return?obj }
測試一波
const?state?=?reactive({ ??a:?1, ??b:?2, ??c:?3 }) const?sum?=?computed(()?=>?{ ??console.log('執(zhí)行計算') ??return?state.a?+?state.b }) console.log(sum.value)?//?3 console.log(sum.value)?//?3 state.a?=?4 console.log(sum.value)?//?3?答案是錯誤的
完美?。?!這下面試官再也難不倒我了?。?!
到此這篇關(guān)于vue面試常考之computed是如何實現(xiàn)的的文章就介紹到這了,更多相關(guān)vue computed內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決獲取數(shù)據(jù)后this.$refs.xxx.toggleRowSelection無效的問題
這篇文章主要介紹了解決獲取數(shù)據(jù)后this.$refs.xxx.toggleRowSelection無效的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10Element Plus暗黑模式及模式自由切換的實現(xiàn)
本文詳細(xì)介紹了如何在使用Vite構(gòu)建的Vue項目中實現(xiàn)ElementPlus暗黑模式及模式切換,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-11-11vue3模塊創(chuàng)建runtime-dom源碼解析
這篇文章主要為大家介紹了vue3模塊創(chuàng)建runtime-dom源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01vue2.0頁面前進(jìn)刷新回退不刷新的實現(xiàn)方法
這篇文章主要介紹了vue2.0頁面前進(jìn)刷新回退不刷新的實現(xiàn)方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07vue中img src 動態(tài)加載本地json的圖片路徑寫法
這篇文章主要介紹了vue中的img src 動態(tài)加載本地json的圖片路徑寫法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2019-04-04