Vue源码探究之状态初始化(2)

initProps

// 定义initProps函数,接收vm,propsOptions两个参数
function initProps (vm: Component, propsOptions: Object) {
 // 赋值propsData,propsData是全局扩展传入的赋值对象
 // 在使用extend的时候会用到,实际开发里运用较少
 const propsData = vm.$options.propsData || {}
 // 定义实例的_props私有属性,并赋值给props
 const props = vm._props = {}
 // 缓存prop键,以便将来props更新可以使用Array而不是动态对象键枚举进行迭代。
 // 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)
 }
 // 遍历props配置对象
 for (const key in propsOptions) {
 // 向缓存键值数组中添加键名
 keys.push(key)
 // 验证prop的值,validateProp执行对初始化定义的props的类型检查和默认赋值
 // 如果有定义类型检查,布尔值没有默认值时会被赋予false,字符串默认undefined
 // 对propsOptions的比较也是在使用extend扩展时才有意义
 // 具体实现可以参考 src/core/util/props.js,没有难点这里不详细解释
 const value = validateProp(key, propsOptions, propsData, vm)

 // 非生产环境下进行检查和提示
 /* istanbul ignore else */
 if (process.env.NODE_ENV !== 'production') {
  // 进行键名的转换,将驼峰式转换成连字符式的键名
  const hyphenatedKey = hyphenate(key)
  // 对与保留变量名冲突的键名给予提示
  if (isReservedAttribute(hyphenatedKey) ||
   config.isReservedAttr(hyphenatedKey)) {
  warn(
   `"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`,
   vm
  )
  }
  // 对属性建立观察,并在直接使用属性时给予警告
  defineReactive(props, key, value, () => {
  if (vm.$parent && !isUpdatingChildComponent) {
   warn(
   `Avoid mutating a prop directly since the value will be ` +
   `overwritten whenever the parent component re-renders. ` +
   `Instead, use a data or computed property based on the prop's ` +
   `value. Prop being mutated: "${key}"`,
   vm
   )
  }
  })
 } else {
  // 非生产环境下直接对属性进行存取器包装,建立依赖观察
  defineReactive(props, key, value)
 }
 // 使用Vue.extend()方法扩展属性时,已经对静态属性进行了代理
 // 这里只需要针对实例化时的属性执行代理操作
 // static props are already proxied on the component's prototype
 // during Vue.extend(). We only need to proxy props defined at
 // instantiation here.
 // 当实例上没有同名属性时,对属性进行代理操作
 // 将对键名的引用指向vm._props对象中
 if (!(key in vm)) {
  proxy(vm, `_props`, key)
 }
 }
 // 开启观察状态标识
 toggleObserving(true)
}

initProps 函数的最主要内容有两点,一是对定义的数据建立观察,二是对数据进行代理,这就是私有变量 _props 的作用,之后获取和设置的变量都是作为 _props 的属性被操作。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/428.html