# data
对于data的处理也是在initState中,如果在options中传递了data,则会调用initData方法
export function initState(vm: Component) {
const opts = vm.$options;
if (opts.data) {
initData(vm);
} else {
observe((vm._data = {}), true /* asRootData */);
}
}
core/instance/state.js
function initData(vm: Component) {
let data = vm.$options.data;
// 组件中的data必须是一个函数
data = vm._data = typeof data === "function" ? getData(data, vm) : data || {};
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
);
}
// proxy data on instance
// 获取data中的所有属性
const keys = Object.keys(data);
const props = vm.$options.props;
const methods = vm.$options.methods;
let i = keys.length;
// 判断data上的属性是否和props/methods 重名
while (i--) {
const key = keys[i];
if (process.env.NODE_ENV !== "production") {
if (methods && hasOwn(methods, key)) {
warn(
`Method "${key}" has already been defined as a data property.`,
vm
);
}
}
if (props && hasOwn(props, key)) {
process.env.NODE_ENV !== "production" &&
warn(
`The data property "${key}" is already declared as a prop. ` +
`Use prop default value instead.`,
vm
);
// 是否以_或$开头
} else if (!isReserved(key)) {
// 把_data中的数据注入到vm实例中
proxy(vm, `_data`, key);
}
}
// observe data
// 响应式对象
observe(data, true /* asRootData */);
}
根据分析可以得知,initData主要做的是:
# 获取 data
由于之前的参数通过了
mergeOptions,所有的data都会被转为function mergedInstanceDataFn,返回一个对像,
生成的函数通过getData来获取:
export function getData(data: Function, vm: Component): any {
// 响应式相关
pushTarget();
try {
return data.call(vm, vm);
} catch (e) {
handleError(e, vm, `data()`);
return {};
} finally {
popTarget();
}
}
通过一个try/catch来执行data函数并且返回,最终统一进行错误处理。
用户定义的data可以是函数或者对象,如果是子组件必须是函数返回一个对象,否则当多次引用子组件会出现引用类型的问题,会在开发环境报错误信息。