这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战
简单总结一下前面三篇内容:数据初始化并对其进行数据劫持,对象和数组都进行了处理
利用此时的Vue
进行实例化
let vm = new Vue({
data() {
return {
name: 'nordon',
age: 12
}
}
});
此时想要获取到data
中的数据,需要借助_data
获取,因为data
并不是直接传递的对象,而是一个函数,此时是不能直接通过$options
获取
vm._data.name;
这种获取方式明显是不够简洁方便的,期望的是可以直接通过vm.name
获取
只需要在数据初始化的时候将数据进行一层代理即可,即vm.name
等价于vm._data.name
proxy
函数实现
function proxy(vm, source, key) {
Object.defineProperty(vm, key, {
get() {
return vm[source][key];
},
set(newVal) {
vm[source][key] = newVal;
},
});
}
在src/state.js
文件中找到initData
函数
function initData(vm) {
// 数据初始化工作
let data = vm.$options.data;
// 对data进行处理
data = vm._data = typeof data === "function" ? data.call(vm) : data;
// 为了让用户更好的使用,直接vm.xxx 取值
for (const key in data) {
proxy(vm, "_data", key);
}
// 通过 Objet.defineProperty() 为属性增加get和set方法
observe(data);
}
此时可以正常使用,但是上面的代码却有一个比较严重的隐患,使用过Vue
的朋友都知道,在Vue
中不仅可以直接通过vm
获取到data
的数据,还可以获取到props
、methods
等的数据,因此data
在代理数据时,需要注意命名冲突的发生
在解决问题之前,先看看两个工具小方法,后面会使用到
检测对象obj是否存在属性key
const hasOwnProperty = Object.prototype.hasOwnProperty
export function hasOwn (obj, key) {
return hasOwnProperty.call(obj, key)
}
检测字符串str 是否已 $、_ 开始的,因为Vue内部的属性和方法常常这么命名,不建议开发者在使用的过程中这么命名
export function isReserved (str) {
const c = (str + '').charCodeAt(0)
return c === 0x24 || c === 0x5F
}
此时对initData
函数代理部分进行重写,最终为
function initData(vm) {
// 数据初始化工作
let data = vm.$options.data;
// 对data进行处理
data = vm._data = typeof data === "function" ? data.call(vm) : data;
// 新增代码 开始
const keys = Object.keys(data);
const props = vm.$options.props;
const methods = vm.$options.methods;
let i = keys.length;
while (i--) {
const key = keys[i];
// methods中存在了相同的key, 将会被data中的数据覆盖
if (methods && hasOwn(methods, key)) {
console.warn(`方法 "${key}" 已经作为 "data" 属性存在`);
}
// props中存在相同的key,则不走代理的逻辑,直接使用props的数据
if (props && hasOwn(props, key)) {
console.warn(`"data" 的属性 "${key}" 已经在 "props"中声明,会被 "props"代替`);
} else if (!isReserved(key)) {
proxy(vm, `_data`, key);
}
}
// 新增代码 结束
// 通过 Objet.defineProperty() 为属性增加get和set方法
observe(data);
}
需要注意:
props
中定义的数据优先级高于data
,methods
中定义的函数优先级低于data
,若是存在相同的key
,最终通过vm.key
获取到的是数据优先级依次为props
、data
、methods
,在开发过程中需要注定命名的冲突问题