stateMixin流程

stateMixin主要是处理跟实例相关的属性和方法,它会在Vue.prototype上定义实例会使用到的属性或者方法,这一节我们主要任务是弄清楚stateMixin的主要流程。在src/core/instance/state.js代码中,它精简后如下所示:

import { set, del } from '../observer/index'
export function stateMixin (Vue) {
  // 定义$data, $props
  const dataDef = {}
  dataDef.get = function () { return this._data }
  const propsDef = {}
  propsDef.get = function () { return this._props }
  Object.defineProperty(Vue.prototype, '$data', dataDef)
  Object.defineProperty(Vue.prototype, '$props', propsDef)

  // 定义$set, $delete, $watch
  Vue.prototype.$set = set
  Vue.prototype.$delete = del
  Vue.prototype.$watch = function() {}
}

我们可以从上面代码中发现,stateMixin()方法中在Vue.prototype上定义的几个属性或者方法,全部都是和响应式相关的,我们来简要分析一下以上代码:

  • $data和$props:根据以上代码,我们发现$data$props分别是_data_props的访问代理,从命名中我们可以推测,以下划线开头的变量,我们一般认为是私有变量,然后通过$data$props来提供一个对外的访问接口,虽然可以通过属性的get()方法去取,但对于这两个私有变量来说是并不能随意set,对于data来说不能替换根实例,而对于props来说它是只读的。因此在原版源码中,还劫持了set()方法,当设置$data或者$props时会报错:
if (process.env.NODE_ENV !== 'production') {
  dataDef.set = function () {
    warn(
      'Avoid replacing instance root $data. ' +
      'Use nested data properties instead.',
      this
    )
  }
  propsDef.set = function () {
    warn(`$props is readonly.`, this)
  }
}
  • $set$deletesetdelete这两个方法被定义在跟instance目录平级的observer目录下,在stateMixin()中,它们分别赋值给了$set$delete方法,而在initGlobalAPI中,也同样使用到了这两个方法,只不过一个是全局方法,一个是实例方法。

  • $watch:在stateMixin()方法中,详细实现了$watch()方法,此方法实现的核心是通过一个watcher实例来监听。当取消监听时,同样是使用watcher实例相关的方法,关于watcher我们会在后续响应式章节详细介绍。

Vue.prototype.$watch = function (
    expOrFn: string | Function,
    cb: any,
    options?: Object
  ): 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) {
      try {
        cb.call(vm, watcher.value)
      } catch (error) {
        handleError(error, vm, `callback for immediate watcher "${watcher.expression}"`)
      }
    }
    return function  () {
      watcher.teardownunwatchFn()
    }
  }

在以上代码分析完毕后,我们可以得到stateMixin如下流程图:

最后更新时间:
贡献者: wangtunan