Vue2.0中的$watch$set$delete源码解析
Posted 登楼痕
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue2.0中的$watch$set$delete源码解析相关的知识,希望对你有一定的参考价值。
$watch的实现就是对Watcher类的封装,在此基础上实现了deep: true, immediate: true可选参数。![](https://image.cha138.com/20221124/d05bc7359b2848a58660c45da5cabd0d.jpg)
export default class Watcher constructor(vm, expOrFn, cb) this.vm = vm; if(typeof expOrFn === 'function') this.getter = expOrFn; else this.getter = parsePath(expOrFn) this.cb = cb; this.value = this.get(); ......immediate参数存在,则直接立即执行一次cb,这个很简单。 最后unwatchFn顾名思义就是把当前watcher实例从正在观察的依赖列表中移除。怎么在Watcher类里实现需要的时候添加,不需要的时候移除呢? 就是用一个let depIds = new Set()集合来判断,如果当前Watcher已经订阅了Dep,则不会重复添加订阅。这个判断,可以防止数据变化时Watcher读取新数据时,重复收集依赖。
export default class Watcher constructor(vm, expOrFn, cb) this.vm = vm; this.deps = []; this.depIds = new Set(); ...... this.cb = cb; this.value = this.get(); ...... addDep(dep) const id = dep.id; if(!this.depIds.has(id)) this.depIds.add(id); // 记录自己以后订阅了 this.deps.push(dep); // 记录自己订阅了哪些Dep dep.addSub(this); // 将自己订阅到Dep中 ......在Dep类里面,也会通过window.target.addDep(this)来记录数据发生变化时,要通知哪些Watcher, 所以Watcher和Dep是多对多关系。 那么teardown()做的事就是遍历deps,然后执行this.deps[i].removeSub(this),removeSub()函数就是将Dep里的Watcher从subs数组中移除,所以数据发生变化时,就不会再通知这个Watcher了。 最后是deep参数的实现逻辑,我们知道deep是深度监听变化,也就是不仅当前数据需要收集依赖,其子数据也要触发依赖收集。那么就在get()函数里, 在window.target=undefined之前,进行递归遍历。递归逻辑很简单。如果不是数组或者对象,或者已经被冻结,那么直接返回什么都不做;接着判断dep.id是否存在,来保证不会重复收集依赖;如果是数组,则遍历数组元素递归调用;如果是Object类型,则通过循环key,递归子值,此时因为会获取子值所以会触发一次getter,也就是触发依赖收集,此时window.target没有清空,所以会执行收集,这也是为什么要写在清空逻辑之前的原因。
![](https://image.cha138.com/20221124/c9f5f460da4941048870dea6784f128e.jpg)
![](https://image.cha138.com/20221124/db5d63f5dade4bfea8e46f6332374071.jpg)
![](https://image.cha138.com/20221124/6f1d7eecbac34b23b80280b0a0a8e20c.jpg)
以上是关于Vue2.0中的$watch$set$delete源码解析的主要内容,如果未能解决你的问题,请参考以下文章
Vue2.0学习—watch和computed对比(三十七)