我们经常使用watch肯定知道它,他和computer一样都是数据发生变化都会触发它。今天我们就来了解一下它的原理。
他的用法
Vue.prototype.$watch = function (
expOrFn: string | (() => any),
cb: any,
options?: Record<string, any>
): Function
这是vuejs源码定义,第一个参数是一个表达式,表示要观察的表达式,或者couputed函数在vuejs实例上的变化。
第二个参数是一个回调函数,调用时会从参数得到新数据(new value)和旧数据(old value)。
第三个参数接受一个对象里面可以传deep或者immediate。deep时为了发现对象内部值的变化,可以在参数指定deep:true。不过注意,监听数组变动不需要。
immediate:设置它为true,将立即以表达式当前值触发回调。而不是等到数据变化才触发回调。
vm.$watch返回一个取消观察函数,用来停止触发回调:
var unwatch = vm.$watch('a', (newVal, oldVal) => {});
unwatch() // 之后取消观察
watch的内部原理
vm. w a t c h 是对 W a t c h e r 的一种封装,通过 w a t c h e r 实现 v m . watch是对Watcher的一种封装,通过watcher实现vm. watch是对Watcher的一种封装,通过watcher实现vm.watch的功能。
但vm.$watch中的参数deep和immeditae是watcher中所没有的。
Vue.prototype.$watch = function (
expOrFn: string | (() => any),
cb: any,
options?: Record<string, any>
): Function {
const vm: Component = this
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options)
}
options = options || {}
options.user = true
const watcher = new Watcher(vm, expOrFn, cb, options)
if (options.immediate) {
const info = `callback for immediate watcher "${watcher.expression}"`
pushTarget()
invokeWithErrorHandling(cb, vm, [watcher.value], vm, info)
popTarget()
}
return function unwatchFn() {
watcher.teardown()
}
}
这是watch的源码。先执行new Watcher来实现vm.$watch的基本功能。
执行完new Wathcer之后,代码判断是否使用immediate参数。如果使用了则立即实行一次cb。
最后,执行一个函数unwatchFn,用来取消观察数据。
实际是执行了teardown()来取消观察数据。是把watcher实例从当前正在观察的状态的依赖列表中移除。