Vue数据绑定简析小结(2)

首先初始化了一个 _watchers 数组,用来存放 watcher ,之后根据实例的 vm.$options ,相继调用 initPropsinitMethodsinitDatainitComputedinitWatch 方法。

initProps

function initProps (vm, propsOptions) {
 const propsData = vm.$options.propsData || {}
 const props = vm._props = {}
 // cache prop keys so that future props updates can iterate using Array
 // instead of dynamic object key enumeration.
 const keys = vm.$options._propKeys = []
 const isRoot = !vm.$parent
 // root instance props should be converted
 if (!isRoot) {
 toggleObserving(false)
 }
 for (const key in propsOptions) {
 keys.push(key)
 const value = validateProp(key, propsOptions, propsData, vm)
 ...
 defineReactive(props, key, value)
 if (!(key in vm)) {
  proxy(vm, '_props', key)
 }
 }
 toggleObserving(true)
}

在这里, vm.$options.propsData 是通过父组件传给子组件实例的数据对象,如 <my-element :item="false"></my-element> 中的 {item: false} ,然后初始化 vm._propsvm.$options._propKeys 分别用来保存实例的 props 数据和 keys ,因为子组件中使用的是通过 proxy 引用的 _props 里的数据,而不是父组件传递的 propsData ,所以这里缓存了 _propKeys ,用来 updateChildComponent 时能更新 vm._props 。接着根据 isRoot 是否是根组件来判断是否需要调用 toggleObserving(false) ,这是一个全局的开关,来控制是否需要给对象添加 __ob__ 属性。这个相信大家都不陌生,一般的组件的 data 等数据都包含这个属性,这里先不深究,等之后和 defineReactive 时一起讲解。因为 props 是通过父传给子的数据,在父元素 initState 时已经把 __ob__ 添加上了,所以在不是实例化根组件时关闭了这个全局开关,待调用结束前在通过 toggleObserving(true) 开启。

之后是一个 for 循环,根据组件中定义的 propsOptions 对象来设置 vm._props ,这里的 propsOptions 就是我们常写的

export default {
  ...
  props: {
    item: {
      type: Object,
      default: () => ({})
    }
  }
}

循环体内,首先

const value = validateProp(key, propsOptions, propsData, vm)

validateProp 方法主要是校验数据是否符合我们定义的 type ,以及在 propsData 里未找到