这是我自己在深入了解 Vue
过程自己思考过的一些问题,特意拿出来记录一下,以免今后遗忘:
1.Vue
把数据转换成响应式数据后,是怎么来触发getter从而收集依赖的
解答:Vue
在初始化的过程中,把数据都转换成响应式数据。在触发生命周期函数beforeMount
之后通过new Watcher()
来观测渲染函数。源码
2.数组和对象的依赖分别保存在哪
解答:Vue
中数组和对象收集依赖都是在getter
中收集。但是触发setter
的地方不一样。
因为Vue
监听数组的变化是通过Array
的原型方法来监听的,所以必须要保证能在原型方法和getter
中都能够获取到 dep ,所以把 dep 保存在 Observer
实例上。(具体的解释请看[响应式原理]())
3.Watcher
监听函数怎么监测函数中所有用到的数据的
解答:当用 Watcher
监听一个函数时,函数里面每一个数据的getter都会触发,并且此时的 Dep.target
是当前的 Watcher
实例,所以每一个数据都会把当前的Watcher
实例收集起来。
4.Watcher
监听一个路径字符串:'a.b.c',会分别监听a、a.b、a.b.c吗
解答:会。因为a、a.b、a.b.c的getter都会触发。
5.当数据变化后,多余的依赖是怎么处理的
解答:当数据变动后肯定会重新触发getter。源码
// Watcher.js get () { pushTarget(this) let value const vm = this.vm try { // 这里触发getter value = this.getter.call(vm, vm) } catch (e) { if (this.user) { handleError(e, vm, `getter for watcher "${this.expression}"`) } else { throw e } } finally { // "touch" every property so they are all tracked as // dependencies for deep watching if (this.deep) { traverse(value) } popTarget() // 这里清理多余的依赖 this.cleanupDeps() } return value}cleanupDeps () { let i = this.deps.length while (i--) { const dep = this.deps[i] if (!this.newDepIds.has(dep.id)) { dep.removeSub(this) } } let tmp = this.depIds this.depIds = this.newDepIds this.newDepIds = tmp this.newDepIds.clear() tmp = this.deps this.deps = this.newDeps this.newDeps = tmp this.newDeps.length = 0}