这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战
响应式系统是Vue中熟为人知的一个重要特性,其中存在一些问题也是被开发者们津津乐道的,比如对于数组的特殊处理就是一个典型问题,很多人在被问到为何Vue中需要对数组进行特殊处理时,部分人的回答既然是:Object.defineProperty
只能劫持对象,不能接触数组,所以需要特殊处理数组
在揭晓答案之前,我们先来看一看简易版本的响应式实现
Object.defineProperty
总所周知的是:在Vue中响应式的核心之一便是Object.defineProperty
,该方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象
语法:
Object.defineProperty(obj, prop, descriptor)
复制代码
- obj:要定义属性的对象
- prop:要定义或修改的属性的名称或
Symbo
- descriptor:要定义或修改的属性描述符
数据劫持
接下来直接上代码,核心代码已注释
/**
* 数据劫持
*/
const defineReactive = (data, key, value) => {
// 递归劫持数据
observe(value);
Object.defineProperty(data, key, {
get() {
console.log("get");
return value;
},
set(newValue) {
console.log("set");
// 若是数据没有变化 则不处理
if (newValue === value) return;
// 递归劫持数据: 若是新赋值的数据是对象 需要继续劫持
observe(newValue);
value = newValue;
},
});
};
/**
* 用于处理数据
*/
const observe = (data) => {
// 不是对象 不需要处理
if (typeof data !== "object" || !data) {
return data;
}
// 遍历对象
Object.keys(data).forEach((key) => {
defineReactive(data, key, data[key]);
});
};
复制代码
接下来定义需要劫持的数据
const obj = {
arr: [1, 2, 3],
name: "nordon",
info: {
age: 12,
},
};
复制代码
将数据劫持
observe(obj);
复制代码
首先验证一下对于常规数据的劫持效果
obj.name;
obj.name = "wy";
obj.info.age = 18
复制代码
此时控制台会依次输出:get、set、get、set
接下来看一下对于数组是否具有劫持效果
obj.arr.unshift(4);
复制代码
上述代码改变了arr
的长度,在其首部增加一位数据,而且会触发多次get、set,证明使用Object.defineProperty
是可以对数组进行数据劫持的,因此对于Vue中对于数组的特殊处理,并不是因为Object.defineProperty
不能劫持数组,而是出于性能的考虑重写了7个数组的方法。