Vue2.x之疑点

这是我本身在深刻了解 Vue 过程本身思考过的一些问题,特地拿出来记录一下,以避免从此遗忘:vue

1.Vue 把数据转换成响应式数据后,是怎么来触发getter从而收集依赖的

解答:Vue 在初始化的过程当中,把数据都转换成响应式数据。在触发生命周期函数beforeMount以后经过new Watcher() 来观测渲染函数。源码git

2.数组和对象的依赖分别保存在哪

解答:Vue 中数组和对象收集依赖都是在getter 中收集。可是触发setter 的地方不同。github

由于Vue 监听数组的变化是经过Array的原型方法来监听的,因此必需要保证能在原型方法和getter中都可以获取到 dep ,因此把 dep 保存在 Observer 实例上。(具体的解释请看响应式原理)express

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。源码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
}
复制代码
相关文章
相关标签/搜索