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