computed: 在初始化子组件构造器的时候,会判断是否有computed属性,然后如果有,就对其进行处理,将对应computed的属性设置在原型上,并且拦截了他的get为createComputedGetter返回值,在原型上定义是为了多组件共享
初始化执行init时,会执行initState,然后执行initComputed,然后创建一个watcher,然后将computed对用的函数传入,赋值给watcher的getter,然后把watcher放在vm._computedWatchers下
然后再render过程,会访问到对应的computed内定义的变量,由于最开始说了get被拦截,所以会走到createComputedGetter,首先我们会拿到初始化的时候定义的watcher
然后执行watcher.evaluate();求值,走到this.get(),然后首先执行pushTarget(this),将Dep.target改为computed Watcher,然后执行this.getter,即computed对应的函数,然后函数里会有对应的响应式变量,所以会走到对应的get逻辑,添加computed Watcher为他的订阅者
然后执行watcher.depend,往watcher里添加订阅者,即组件的渲染watcher
当数据发生变化时,会触发notify,通知变化,同之前,会走到watcher.run,执行this.get(),重新收集依赖等,然后判断值是否改变了,然后更新
watch: watch流程较为简单,初始化执行init时,执行initState,然后执行initWatcher,然后执行createWatcher逻辑,其实就是执行了一次vm.$watch,然后执行new Watcher,注意此时expOrFn可能是一个string,然后执行parsePath逻辑,将返回的函数赋值getter,然后有执行get,然后再去执行getter,执行getter会将vm传入,然后这个时候obj就是vm,所以后面会访问到obj上的变量,所以触发getter以来收集,由于之前执行get()时,Dep.target为userWatcher,所以就会收集这个userWatcher,然后变化的时候,在通知更新
function parsePath (path) {
if (bailRE.test(path)) {
return
}
var segments = path.split('.');
return function (obj) {
for (var i = 0; i < segments.length; i++) {
if (!obj) { return }
obj = obj[segments[i]];
}
return obj
}
}