Object.defineProperty() 的不足
如果有同学对
Object.defineProperty()
还不是很熟悉,建议先看看这篇文章:五分钟快速搞定 Object.defineProperty()。
众所周知 Object.defineProperty()
在数组监控方面不足,哪里不足?我们来看下面这个例子:
let data = {
list: []
}
Object.keys(data).forEach(function (key) {
let value = data[key];
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get() {
return value;
},
set(newValue) {
console.log(`Array Changed`);
value = newValue;
return true;
}
})
})
data.list.push(1); //---> A 行代码
// data.list = [1, 2, 3]; //---> B 行代码
console.log(data.list);
既然是对数组的监控,那么就该能监测到数组元素的增加或者删除。因此,向 list
中增加元素的时候,理应会有打印 Array Changed
。
但实际情况是,数组的确发生了改变(增加了一个元素),但并没有打印出 Array Changed
,因此并没有检测到数组的变化。只有在 B 行代码被解开之后,控制台才会打印出 Array Changed
。
因此,我们可以大胆得猜测:当监控数据对象中的 数组 的时候,实质上是监控数组的地址,地址不变也就不会被监测到。所以,我们向 list
里 push
元素的时候并没有触发打印;当我们直接替换 list
对象的时候就触发了打印。这就是 Object.defineProperty()
在数组监控方面的不足。
那么,如何使 Object.defineProperty()
在弥补先天不足的情况下实现对数组的精准监控。
改进一下 Object.defineProperty 的使用
let arrayMethod = Object.create(Array.prototype);
['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (method) {
Object.defineProperty(arrayMethod, method, {
enumerable: true,
configurable: true,
value: function () {
let args = [...arguments]
Array.prototype[method].apply(this, args);
console.log(`operation: ${method}`)
// 这是 vue 中的代码,目的是监听动作
dep.notify();
}
})
});
上面代码,仅仅是数据中的数组对象的原型被修改掉了,并不会影响到全局的数组对象。
Proxy 的诞生
因为 Object.defineProperty()
在数组监控方面的不足,所以后期发展出了 Proxy
(代理)。
来 一次性搞懂 ES6 的 Proxy 看看,Proxy 如何帮助我们实现数据监控,解决问题。
网友评论