这是我自己在深入了解 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}