function initProps (vm: Component, propsOptions: Object) { // 根组件可能存在的 propsData 数据 const propsData = vm.$options.propsData || {} // 普通组件使用方式时传递的 props 数据 const props = vm._props = {} // cache prop keys so that future props updates can iterate using Array // instead of dynamic object key enumeration. // props 的 key 值集合 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) // 用来校验名字(key)给定的 prop 数据是否符合预期的类型,并返回相应 prop 的值(或默认值)。 const value = validateProp(key, propsOptions, propsData, vm) /* istanbul ignore else */ // 非生产环境时的一些校验报错信息,更有助于开发者 debug if (process.env.NODE_ENV !== 'production') { // 如果相关 key 值以及预设,则抛出错误 const hyphenatedKey = hyphenate(key) if (isReservedAttribute(hyphenatedKey) || config.isReservedAttr(hyphenatedKey)) { warn( `"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`, vm ) } // 如果试图更新 props 值则抛出错误 defineReactive(props, key, value, () => { if (!isRoot && !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 { // 简单地使 props 具备响应式(非深度) defineReactive(props, key, value) } // static props are already proxied on the component's prototype // during Vue.extend(). We only need to proxy props defined at // instantiation here. // 代理访问那些未定义的 props if (!(key in vm)) { proxy(vm, `_props`, key) } } toggleObserving(true)}
validateProp
export function validateProp ( key: string, propOptions: Object, propsData: Object, vm?: Component): any { // 取出 prop 配置 const prop = propOptions[key] // 当前 prop 是否为传递 const absent = !hasOwn(propsData, key) // 取出对应的值 let value = propsData[key] // 判断当前 prop 类型是否有 boolean 类型 const booleanIndex = getTypeIndex(Boolean, prop.type) // 如果是或者有 boolean 类型 if (booleanIndex > -1) { if (absent && !hasOwn(prop, 'default')) { // 未传值且没有设置默认值则设置成 false value = false } else if (value === '' || value === hyphenate(key)) { // 当 prop 是一个空字符串,或者是一个名字由驼峰转连字符后与值为相同字符串的 prop // 并且 boolean 的权重高于 string,则设置成 true const stringIndex = getTypeIndex(String, prop.type) if (stringIndex < 0 || booleanIndex < stringIndex) { value = true } } } // 如果值为 undefined if (value === undefined) { // 获取默认值 value = getPropDefaultValue(vm, prop, key) // 将默认值变成响应式数据 const prevShouldObserve = shouldObserve toggleObserving(true) observe(value) toggleObserving(prevShouldObserve) } // props 的验证抛错 if ( process.env.NODE_ENV !== 'production' && // skip validation for weex recycle-list child component props !(__WEEX__ && isObject(value) && ('@binding' in value)) ) { assertProp(prop, key, value, vm, absent) } return value}