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 的属性被操作。