Vue源码学习之initState
这次学习的initState方法,这个方法应该是整个Vue实例初始化过程中最重要的方法之一了,我们经常使用的属性,包括像是data,props,methods,watch,computed等都是在这个方法中进行初始化的。该方法介于beforeCreate和created两个钩子之间,所以在beforeCreate的时候我们还无法访问到Vue实例上的data,props,methods等属性。所以让我们看一下它的代码吧:
function initState (vm: Component) {
vm._watchers = []
const opts = vm.$options
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
if (opts.data) {
initData(vm)
} else {
observe(vm._data = {
}, true /* asRootData */)
}
if (opts.computed) initComputed(vm, opts.computed)
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
}
}
整个方法没有什么特别的,对属性进行初始化的部分都是交由其他的方法实现,下面一个个分析这些初始化的过程。
1、initProps
// 存放父组件传入子组件的props
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的数组,就算props的值是空的,key也会存在里面
const keys = vm.$options._propKeys = []
const isRoot = !vm.$parent
前几行就是一些常规的赋值,propsData是父组件子组件传的参数,_props是最后存props的值的对象,keys是props的key存储的地方,我们可以通过这个数组去遍历props,isRoot则是判断是不是根元素。
for (const key in propsOptions) {
keys.push(key)
// 校验props,包括对类型的校验以及产生最后的属性值
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
)
}
// 将props变成可响应的,非生产环境中,如果用户修改props,发出警告
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: "${