# watch

export default {
  watch: {
    name(newName) {...}
  }
}

其实它只是this.$watch这个API的一种封装:

export default {
  created() {
    this.$watch('name', newName => {...})
  }
}

看下watch的整个过程:

// 1. 初始化所有状态时
function initState(vm) {  
  vm._watchers = []  // 当前实例watcher集合
  const opts = vm.$options  // 合并后的属性
  
  if(opts.watch) {  // 如果有定义watch属性
    initWatch(vm, opts.watch)  // 执行初始化方法
  }
}

// 2. // 初始化watch
function initWatch (vm, watch) {  
  for (const key in watch) {  // 遍历watch内多个监听属性
    const handler = watch[key]  // 每一个监听属性的值
    if (Array.isArray(handler)) {  // 如果该项的值为数组
      for (let i = 0; i < handler.length; i++) {
        createWatcher(vm, key, handler[i])  // 将每一项使用watcher包装
      }
    } else {
      createWatcher(vm, key, handler) // 不是数组直接使用watcher
    }
  }
}


// 3. 创建Watcher
function createWatcher (vm, expOrFn, handler, options) {
  if (isPlainObject(handler)) { // 如果是对象,参数移位
    options = handler  
    handler = handler.handler
  }
  if (typeof handler === 'string') {  // 如果是字符串,表示为方法名
    handler = vm[handler]  // 获取methods内的方法
  }
  return vm.$watch(expOrFn, handler, options)  // 封装
}

// 4. $watch
Vue.prototype.$watch = function(expOrFn, cb, options = {}) {
  const vm = this
  if (isPlainObject(cb)) {  // 如果cb是对象,当手动创建监听属性时
    return createWatcher(vm, expOrFn, cb, options)
  }
  
  options.user = true  // user-watcher的标志位,传入Watcher类中
  const watcher = new Watcher(vm, expOrFn, cb, options)  // 实例化user-watcher
  
  if (options.immediate) {  // 立即执行
    cb.call(vm, watcher.value)  // 以当前值立即执行一次回调函数
  }  // watcher.value为实例化后返回的值
  
  return function unwatchFn () {  // 返回一个函数,执行取消监听
    watcher.teardown()
  }
}

// 5. Watcher
class Watcher {
  constructor(vm, expOrFn, cb, options) {
    this.vm = vm
    vm._watchers.push(this)  // 添加到当前实例的watchers内
    this.getter = parsePath(expOrFn)  // 返回的方法
    
    this.value = this.get()  // 执行get
    
    if(options) {
      this.deep = !!options.deep  // 是否深度监听
      this.user = !!options.user  // 是否是user-wathcer
      this.sync = !!options.sync  // 是否同步更新
    }
    
    this.active = true  // // 派发更新的标志位
    this.cb = cb  // 回调函数
    
    if (typeof expOrFn === 'function') {  // 如果expOrFn是函数
      this.getter = expOrFn
    } else {
      this.getter = parsePath(expOrFn)  // 如果是字符串对象路径形式,返回闭包函数
    }
    
    ...
    
  }

  get() {
    pushTarget(this)  // 将当前user-watcher实例赋值给Dep.target,读取时收集它
    
    let value = this.getter.call(this.vm, this.vm)  // 将vm实例传给闭包,进行读取操作
    
    if (this.deep) {  // 如果有定义deep属性
      traverse(value)  // 进行深度监听
    }
    
    popTarget()
    return value  // 返回闭包读取到的值,参数immediate使用的就是这里的值
  }

  update() {  // 执行派发更新
    if(this.sync) {  // 如果有设置sync为true
      this.run()  // 不走nextTick队列,直接执行
    } else {
      queueWatcher(this)  // 否则加入队列,异步执行run()
    }
  }

    run() {
    if (this.active) {
      this.getAndInvoke(this.cb)  // 传入回调函数
    }
  }
  
  getAndInvoke(cb) {
    const value = this.get()  // 重新求值
    
    if(value !== this.value || isObject(value) || this.deep) {
      const oldValue = this.value  // 缓存之前的值
      this.value = value  // 新值
      if(this.user) {  // 如果是user-watcher
        cb.call(this.vm, value, oldValue)  // 在回调内传入新值和旧值
      }
    }
  }
}

watch就是创建了一个option.user=true的Watcher,当监听对象发生变化时,只行额外的回调函数,并把newVal和oldVal传给回调函数。

watch可以取消监听

export default {
  data() {
    return {
      name: 'cc'
    }  
  },
  created() {
    this.unwatch = this.$watch('name', newName => {...})
    this.unwatch()  // 取消监听
  }
}