vm.init,先为computed变量(假设是age,并在computed方法中依赖于另一个变量vm.factor)初始化,age会关联一个watcher(假设为cWatcher,lazy为true),vm.age的get方法被重写,cWatcher的dirty属性被置为true。其getter属性指向的是computed中定义的age的get方法,其cb属性指向的是noop。
接下来initWatch,再new 一个Watcher(假设叫wWatcherlazy为false),其getter属性指向的方法实际上调用的是vm.age的get方法(被重写之后的那个),其cb属性指向的是options对象里watch中age的hander方法。因为wWatcher的lazy属性为false,那么在构造方法中会直接调用wWatcher的get方法,逻辑是把当前wWatcher放到Dep的栈顶,调用getter方法,也就是vm.age的get方法,发现cWatcher.dirty为true(注意这里由wWatcher变成了cWatcher),调用cWatcher的get方法,发现cWatcher的dirty为true,那么调用cWatcher的evaluate方法,this.value=get()中,把cWatcher入栈,调用vm.age的get方法计算age的值,此时例如vm.factor在initComputed之前调用过initData的,所以factor的get方法中,会调用defineReactive方法闭包中的Dep,收集cWatcher(同时cWatcher也会收集这些Dep),那么以后factor的set方法被执行设置成另一个值的时候,会调用cWatcher的update方法。从cWatcher的evaluate方法中出来,有if(Dep.target).....的方法,注意此时的Dep.target是wWatcher了,这时候cWatcher的depend方法,会让cWatcher刚才调用vm.age收集到的Dep,例如factor的那个闭包中的Dep,和wWatcher相互收集。那么此时factor的Dep中既收集到了cWatcher,又收集到了wWatcher。
如果接下来,改变factor为另一个值。那么会先后调用cWatcher和wWatcher的update方法,先说前者,因为是lazy的,所以仅仅把dirty设置为true。接下来调用wWatcher的update,把它的run方法放到微任务队列中执行,先执行wWatcher的get方法,调用vm.age的被重写的get方法,获取value,此时如果factor的改变导致age的值改变了,那么这个value和wWatcher中保存的value不同,回往下执行wWatcher的cb也就是options对象里watch中age的hander方法,这个也是合理的。但是如果factor的改变并没有导致age的值改变,将不会调用cb。
综上所述,之所以computed的变量的watch会变得比普通变量的watch复杂的多,这是因为普通变量的Dep存在与defineReactive方法的闭包中,get方法收集watcher,set方法响应。而computed的变量并没有这个Dep和闭包,只有借助它依赖的变量进行对cWatcher和wWatcher的收集和响应。