Vue数据代理之data源码分析
Vue中的数据代理
通过vm对象来代理data对象中的属性实现读写
// 初始化状态
function initState(vm) {
// 获取Vue实例中 属性 信息
var opts = vm.$options;
// 判断 props 是否被进行配置
if (opts.props)
initProps$1(vm, opts.props);
initSetup(vm);
// 判断 methods 是否被配置
if (opts.methods)
initMethods(vm, opts.methods);
// 判断 data 是否被配置
if (opts.data) {
// 初始化 data
initData(vm);
}
else {
var ob = observe((vm._data = {}));
ob && ob.vmCount++;
}
if (opts.computed)
initComputed$1(vm, opts.computed);
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch);
}
}
// 初始化 data
function initData(vm) {
// 获取 vue实例中的 data
var data = vm.$options.data;
// 如果data是函数就直接获得 data中的数据 否则直接拿设置的对象
// vm._data 与 vm.$options.data 指向 同一个引用,此时操作 vm._data中的数据就是操作Vue实例中的data
data = vm._data = isFunction(data) ? getData(data, vm) : data || {};
// 判断data是否是对象
if (!isPlainObject(data)) {
data = {};
warn$2('data functions should return an object:\n' +
'https://v2.vuejs.org/v2/guide/components.html#data-Must-Be-a-Function', vm);
}
// vue实例的数据代理
// 获取vue实例(vm.$options.data)中 data对象 的 属性名数组
var keys = Object.keys(data);
var props = vm.$options.props;
var methods = vm.$options.methods;
// 获取属性名数组的长度
var i = keys.length;
// 循环遍历
while (i--) {
// 获取当前索引下的属性名
var key = keys[i];
{
// 检查当前的data对象中属性的属性名是否已经在 methods 中被使用
if (methods && hasOwn(methods, key)) {
warn$2("Method \"".concat(key, "\" has already been defined as a data property."), vm);
}
}
// 检查当前的data对象中属性的属性名是否已经在 props 中被使用
if (props && hasOwn(props, key)) {
warn$2("The data property \"".concat(key, "\" is already declared as a prop. ") +
"Use prop default value instead.", vm);
}
// 只要元素不是以 _ 或 $ 开头就执行数据代理
else if (!isReserved(key)) {
// 数据代理,将 vm.$options.data 中的 属性名 添加到 vm._data上
proxy(vm, "_data", key);
}
}
// 监测 data 数据变化
var ob = observe(data);
ob && ob.vmCount++;
}
// 数据代理
/* targrt: 目标对象
* sourceKey: 要添加的属性
* key: 属性的值
*/
function proxy(target, sourceKey, key) {
// 设置数据代理的属性值的get方法
sharedPropertyDefinition.get = function proxyGetter() {
// 等效于 return this.sourceKey.key;
return this[sourceKey][key];
};
// 设置数据代理的属性值的set方法
sharedPropertyDefinition.set = function proxySetter(val) {
// 等效于 this.sorceKey.key = val;
this[sourceKey][key] = val;
};
// 数据代理 给vm添加属性 使之可以以 vm.name 的形式操作 vm._data中的数据,并且在标签中可以使用{{name}}的形式来访问 vm.$options.data.name,若不为vm设置数据代理则在标签中就要使用{{_data.name}}的形式来访问属性 vm.$options.data.name,相比较之下设置数据代理之后操作更方便快捷
Object.defineProperty(target, key, sharedPropertyDefinition);
}
// 数据代理的属性值
var sharedPropertyDefinition = {
// 可以被遍历
enumerable: true,
// 属性可以被删除
configurable: true,
get: noop,
set: noop
};
/**
* 检查字符串是否以 _ 或者 $ 开头
*/
function isReserved(str) {
var c = (str + '').charCodeAt(0);
return c === 0x24 || c === 0x5f;
}
通过源码可知,如果vue实例中(之后用vm代替)的$options.data有值,则执行 vm._data = vm.$options.data,因为 vm._data 与 vm.$options.data为同一个引用,所以修改 vm.$options.data对象中的属性值的时候,vm._data对象中的属性也会发生改变,反之亦然;最后执行了 proxy(vm, _data, key)
方法,而在proxy方法中做的事情就是为每个属性设置get、set方法最后再将此属性代理至vm也就是this,至此我们就可以使用 this.属性名
或者在标签中使用 {{属性名}}
来访问Vue配置项中的data数据。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix