Vue.js---watch 的实现原理
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();
}