$watche方法的两个参数:
第一个参数两种可能:
- 传入被观察对象表达式(字符串),比如
'a,b,c','$route' - 如果表达式无法表示需要观察的内容,可以通过函数返回,比如:
() => this.a + this.b
第一个参数干什么用的?
通过vue源码可得,new Watcher的流程:
第一步:拿到第一个参数,如果是函数,直接拿到函数,如果不是函数,转换为函数(parsePath),这个作为getter,先不调用,只备用
// parse expression for getter
if (typeof expOrFn === 'function') {
this.getter = expOrFn
} else {
this.getter = parsePath(expOrFn)
if (!this.getter) {
this.getter = noop // noop就是空
}
}
第二步:调用Watcher类里的this.get:
this.value = this.lazy
? undefined
: this.get()
插入下源代码:
/**
* Evaluate the getter, and re-collect dependencies.
*/
get () {
pushTarget(this)
let value
const vm = this.vm
try {
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
}
第三步:上面的源码就是this.get方法,看看里面有什么,这里第一句就是把当前watcher实例设置成Dep.target(姑且理解为全局变量),:
pushTarget(this)
关于
Dep.target:回忆一下,在defineProperty的get里,是不是也用到了这Dep.target,对了!defineProperty里就是取这个Dep.target值,watcher只有一处取值,一处赋值,那么这个值在哪里赋上去的呢?对了!就是在这个pushTarget里
第四步:Dep.target已经有值了,调用一下之前备用的getter(上面第一步),这样就能触发defineProperty的get了,触发以后,就把这个watcher添加到get对应数据的deps依赖数组里了
value = this.getter.call(vm, vm)
这样,再修改这个设置了defineProperty的响应式数据,就能触发这个数据绑定的所有watcher依赖了