所以我们打开 core/instance/state.js 文件 找到 initState 函数
export function initState (vm: Component) {
vm._watchers = [] //储存watcher对象
const opts = vm.$options //options引用
if (opts.props) initProps(vm, opts.props) //初始化props
if (opts.methods) initMethods(vm, opts.methods) //初始化方法
if (opts.data) {
initData(vm) //初始化data
} else {
observe(vm._data = {}, true /* asRootData */) //这里是data为空时observe 函数观测一个空对象:{}
}
if (opts.computed) initComputed(vm, opts.computed) //初始化computed
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
} //初始化watch
}
现在要看的是这一段
if (opts.data) {
initData(vm) //初始化data
} else {
observe(vm._data = {}, true /* asRootData */) //这里是data为空时observe 函数观测一个空对象:{}
}
初始化data的过程 首先判断 opts.data 是否存在,即 data 选项是否存在,如果存在则调用 initData(vm) 函数初始化 data 选项,否则通过 observe 函数观测一个空的对象,并且 vm._data 引用了该空对象。其中 observe 函数是将 data 转换成响应式数据的核心入口,
在core/instance/state.js 文件,initData 函数的一开始是这样一段代码
let data = vm.$options.data //定义data对象
data = vm._data = typeof data === 'function'
? getData(data, vm) 执行这个函数
: data || {}
//这里是初始化data第一步就是执行data的构造函数 因为之前都是包装成函数的 但是为什么还要判断呢
因为 beforeCreate 生命周期钩子函数是在 mergeOptions 函数之后 initData 之前被调用的,如果在 beforeCreate 生命周期钩子函数中修改了 vm.$options.data 的值,那么在 initData 函数中对于 vm.$options.data 类型的判断就是必要的了
export function getData (data: Function, vm: Component): any {
// #7573 disable dep collection when invoking data getters
pushTarget()
try {
return data.call(vm, vm)
} catch (e) {
handleError(e, vm, `data()`)
return {}
} finally {
popTarget()
}
} 这里的pushTarget(),popTarget()其实是在props数据和data初始化时的收集冗余依赖的 等到后面再说
总直到目前位置正常情况就是通过getData函数获取data选项的数据对象 然后回到initData中
data = vm._data = getData(data, vm)
这里重写了data和vm实例上的_data
接着是个if
if (!isPlainObject(data)) {
data = {}
process.env.NODE_ENV !== 'production' && warn(
'data functions should return an object:\n' +
'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
vm
)
}
判断data对象是否是个纯对象不是就在生产环境打出警告
再往下是这样的一串代码
const keys = Object.keys(data) //获取data所有的键
const props = vm.$options.props //获取props引用
const methods = vm.$options.methods //获取methods引用
let i = keys.length //遍历key
while (i--) {
const key = keys[i]
if (process.env.NODE_ENV !== 'production') {
if (methods && hasOwn(methods, key)) { //methods不能和data重名
warn(
`Method "${key}" has already been defined as a data property.`,
vm
)
}
}
if (props && hasOwn(props, key)) {
//props不能和data重名
process.env.NODE_ENV !== 'production' && warn(
`The data property "${key}" is already declared as a prop. ` +