这是我本身在深刻了解 Vue
过程本身思考过的一些问题,特地拿出来记录一下,以避免从此遗忘:vue
Vue
把数据转换成响应式数据后,是怎么来触发getter从而收集依赖的解答:Vue
在初始化的过程当中,把数据都转换成响应式数据。在触发生命周期函数beforeMount
以后经过new Watcher()
来观测渲染函数。源码git
解答:Vue
中数组和对象收集依赖都是在getter
中收集。可是触发setter
的地方不同。github
由于Vue
监听数组的变化是经过Array
的原型方法来监听的,因此必需要保证能在原型方法和getter
中都可以获取到 dep ,因此把 dep 保存在 Observer
实例上。(具体的解释请看响应式原理)express
Watcher
监听函数怎么监测函数中全部用到的数据的解答:当用 Watcher
监听一个函数时,函数里面每个数据的getter都会触发,而且此时的 Dep.target
是当前的 Watcher
实例,因此每个数据都会把当前的Watcher
实例收集起来。数组
Watcher
监听一个路径字符串:'a.b.c',会分别监听a、a.b、a.b.c吗解答:会。由于a、a.b、a.b.c的getter都会触发。函数
解答:当数据变更后确定会从新触发getter。源码this
// 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
}
复制代码