Object.defineProperty可以劫持数组吗?
响应式系统是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个数组的方法。
作者:Nordon
链接:https://juejin.cn/post/7026910654237769735