4.7 watch 的實現原理
watch本質上就是使用了effect以及options.scheduler
定義watch函數:
// watch函數:傳入參數source以及回調函數function watch(source , cb) {effect(() => source.foo,{scheduler(){// 回調函數cb()}})}
watch接收兩個參數分別是source和cb
source
是一個對象,我們希望監聽它的foo
屬性的變化。cb
是一個回調函數,當source.foo
發生變化時,這個回調函數會被執行。
watch的使用:
// 使用watch函數watch(obj , () => {console.log('值發生改變')})// 修改響應數據的值,導致回調函數執行obj.foo++
值發生改變
**改為更加通用:**除了foo發生改變,其他的發生改變也可以
修改思路:使用函數對傳入的對象循環讀取,traverse函數:傳入對象以及一個set集合(存儲已經訪問過的),判斷類型,類型過關就進行遍歷。
// traverse:值以及讀取放入的setfunction traverse(value , seen = new Set){// 如果要讀取的數據是原始值,或者已經讀取過了,那么什么都不做if(typeof value !== 'object' || value === null || seen.has(value)){return;}// 暫時僅考慮value是一個對象,遍歷valuefor(const k in value){traverse(value[k] , seen);}}// watch函數:傳入參數source以及回調函數function watch(source , cb) {effect(// traverse() => traverse(source),{scheduler(){// 回調函數cb()}})}
壯大watch—getter函數:
修改思路:定義一個getter,如果source是函數類型直接使用getter函數,如果不是則遞歸調取
// watch函數:傳入參數source以及回調函數function watch(source , cb) {// 定義getterlet getter if(typeof source === 'function'){getter = source}else {getter = () => traverse(source)}effect(() => getter(),{scheduler(){// 回調函數cb()}})}
重要功能—新舊值
修改思路:這時候要拿到effect的返回參數,返回參數就是oldval,最核心的改動就是添加了懶加載lazy創建了一個懶加載effect,需要的時候才會執行,在值發生改變時,更新新值和舊值
// watch函數:傳入參數source以及回調函數function watch(source , cb) {// 定義getterlet getter if(typeof source === 'function'){getter = source}else {getter = () => traverse(source)}// 定義新舊值let newVal , oldValconst effectFn = effect(() => getter(),{lazy: true,scheduler(){// 值發生改變會發生,此時就有新值了newVal = effectFn()// 回調函數,傳入新舊值cb(oldVal , newVal)// 一定要記得更新舊值oldVal = newVal}})// 調用effectFn就是舊值oldVal = effectFn();}
source以及回調函數
function watch(source , cb) {
effect(
// traverse
() => traverse(source),
{
scheduler(){
// 回調函數
cb()
}
}
)
}
**壯大watch---getter函數:**修改思路:定義一個getter,如果source是函數類型直接使用getter函數,如果不是則遞歸調取
// watch函數:傳入參數source以及回調函數
function watch(source , cb) {// 定義getterlet getter if(typeof source === 'function'){getter = source}else {getter = () => traverse(source)}effect(() => getter(),{scheduler(){// 回調函數cb()}})
}
**重要功能---新舊值**修改思路:這時候要拿到effect的返回參數,返回參數就是oldval,最核心的改動就是添加了懶加載lazy創建了一個懶加載effect,需要的時候才會執行,在值發生改變時,更新新值和舊值
// watch函數:傳入參數source以及回調函數
function watch(source , cb) {// 定義getterlet getter if(typeof source === 'function'){getter = source}else {getter = () => traverse(source)}// 定義新舊值let newVal , oldValconst effectFn = effect(() => getter(),{lazy: true,scheduler(){// 值發生改變會發生,此時就有新值了newVal = effectFn()// 回調函數,傳入新舊值cb(oldVal , newVal)// 一定要記得更新舊值oldVal = newVal}})// 調用effectFn就是舊值oldVal = effectFn();
}