就会运行到劫持的set函数里:
Object.defineProperty(data, key, {
set(newVal) {
val = newVal
dep.notify()
}
})
此时在控制台中打印出dep这个变量,它内部的deps属性果然存储了一个Watcher的实例。

运行了dep.notify以后,就会触发这个watcher的update方法,也就会再去重新执行一遍渲染函数了,这个时候视图就刷新了。
computed
在实现了reactive这个基础api以后,就要开始实现computed这个api了,这个api的用法是这样:
const data = reactive({
number: 1
})const numberPlusOne = computed(() => data.number + 1)
// 渲染函数watcher
new Watcher(() => {
document.getElementById('app2').innerHTML = `
computed: 1 + number 是 ${numberPlusOne.value}
`
})
vue内部是把computed属性定义在vm实例上的,这里我们没有实例,所以就用一个对象来存储computed的返回值,用.value来拿computed的真实值。
这里computed传入的其实还是一个函数,这里我们回想一下Watcher的本质,其实就是存储了一个需要在特定时机触发的函数,在Vue内部,每个computed属性也有自己的一个对应的watcher实例,下文中叫它computedWatcher
先看渲染函数:
// 渲染函数watcher
new Watcher(() => {
document.getElementById('app2').innerHTML = `
computed: 1 + number 是 ${numberPlusOne.value}
`
})
这段渲染函数执行过程中,读取到numberPlusOne的值的时候
首先会把Dep.target设置为numberPlusOne所对应的computedWatcher
computedWatcher的特殊之处在于
渲染watcher只能作为依赖被收集到其他的dep筐子里,而computedWatcher实例上有属于自己的dep,它可以收集别的watcher作为自己的依赖。
惰性求值,初始化的时候先不去运行getter。
export default class Watcher {
constructor(getter, options = {}) {
const { computed } = options
this.getter = getter
this.computed = computed if (computed) {
this.dep = new Dep()
} else {
this.get()
}
}
}
其实computed实现的本质就是,computed在读取value之前,Dep.target肯定此时是正在运行的渲染函数的watcher。
先把当前正在运行的渲染函数的watcher作为依赖收集到computedWatcher内部的dep筐子里。
把自身computedWatcher设置为 全局Dep.target,然后开始求值:
求值函数会在运行
() => data.number + 1










