
我们经常使用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实例从当前正在观察的状态的依赖列表中移除。



















