To understand the implementation process of Watch, let’s take a look at several ways of using watch

An object whose key is the expression to observe and whose value is the corresponding callback function. The value can also be a method name, or an object that contains options. The Vue instance will call $watch() at instantiation time, iterating through each property of the Watch object.

var vm = new Vue({ 
data: { 
    a: 1.b: 2.c: 3.d: 4.e: { f: { g: 5}}},watch: { 
a: function (val, oldVal) { 
    console.log('new: %s, old: %s', val, oldVal) 
}, 
/ / the method name
b: 'someMethod'.// This callback is called whenever the property of any object being listened on changes, no matter how deeply nested it is
c: {
handler: function (val, oldVal) { / *... * / }, 
deep: true 
}, 
// This callback will be invoked immediately after the listening starts
d: { 
handler: 'someMethod'.immediate: true 
}, 
// You can pass in an array of callbacks, which will be called one by one
e: [ 
'handle1'.function handle2 (val, oldVal) { / *... * / },
{ handler: function handle3 (val, oldVal) { / *... * / }, 
/ *... * /}].// watch vm.e.f's value: {g: 5} 
'e.f': function (val, oldVal) { / *... * / } 
}
})
vm.a = 2 // => new: 2, old: 1
Copy the code

Next, let’s sort out the process of Watch by following the source code

  • Initialize watch in state.js
export function initState (vm: Component) {
  vm._watchers = []
  const opts = vm.$options
  if (opts.props) initProps(vm, opts.props)
  if (opts.methods) initMethods(vm, opts.methods)
  if (opts.data) {
    initData(vm)
  } else {
    observe(vm._data = {}, true /* asRootData */)}if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch) initWatch(vm, opts.watch)
}
Copy the code
function initWatch (vm: Component, watch: Object) {
  for (const key in watch) {
    const handler = watch[key]
    if (Array.isArray(handler)) {
      for (let i = 0; i < handler.length; i++) {
        createWatcher(vm, key, handler[i])
      }
    } else {
      createWatcher(vm, key, handler)
    }
  }
}
Copy the code

Here, several ways of writing watch are adapted. CreateWatcher is finally called

function createWatcher (vm: Component, key: string, handler: any) {
  let options
  if (isPlainObject(handler)) {
    options = handler
    handler = handler.handler
  }
  if (typeof handler === 'string') {
    handler = vm[handler]
  }
  vm.$watch(key, handler, options)
}
Copy the code

Here we see that the watch function is called, so where is this function defined? Where is the watch function defined in the stateMixin function? Where is the watch function defined in the stateMixin function? Watch is already mounted to the VM in the stateMixin function

Vue.prototype.$watch = function (
    expOrFn: string | Function,
    cb: Function, options? :Object
  ) :Function {
    const vm: Component = this
    options = options || {}
    options.user = true
    const watcher = new Watcher(vm, expOrFn, cb, options)
    if (options.immediate) {
      cb.call(vm, watcher.value)
    }
    return function unwatchFn () {
      watcher.teardown()
    }
  }
Copy the code

Here we see that the $watch function returns a function. The returned function execution cancels the added observation. Const watcher = new watcher (VM, expOrFn, CB, options) adds observed values, and corresponding callback functions. For details, please refer to the previous article juejin.cn/post/699458…