状态数据初始化

目录

该章节要解答的疑惑有:

  • 为什么通过vm.xxx可以访问到propsdata数据?

initState

组件实例化的过程中,会在vm._init里调用initState()对组件实例上的状态数据进行初始化,包括:

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 && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

proxy

无论是组件的props数据还是data数据,最终都可以在组件实例vm上访问到,因为在initPropsinitData时都调用了proxyvm._propsvm._data上的数据都代理到了vm上。

// initProps 里
proxy(vm, `_props`, key)

// initData 里
proxy(vm, `_data`, key)
1
2
3
4
5

其实proxy的实现特别简单,就是通过Object.definePropertyvm上新增加了一属性,属性访问器描述符的get特性就是获取vm._props[key](以props为例)的值并返回,属性的访问器描述符的set特性就是设置vm._props[key]的值。

因此,我们最终在访问props时,对vm.xxx的读写实际上就是对vm._props.xxx的读写。data也是同理。

const sharedPropertyDefinition = {
  enumerable: true,
  configurable: true,
  get: noop,
  set: noop
}

export function proxy (target: Object, sourceKey: string, key: string) {
  sharedPropertyDefinition.get = function proxyGetter () {
    return this[sourceKey][key]
  }
  sharedPropertyDefinition.set = function proxySetter (val) {
    this[sourceKey][key] = val
  }
  Object.defineProperty(target, key, sharedPropertyDefinition)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

computed也是经过类似的处理,只是getset不一样而已。