「Vue系列」之为什么用Proxy取代Object.defineProperty?
相信大部分同学都知道,vue2.x大概就是通过Object.defineProperty实现数据劫持,然后结合订阅发布者模式实现响应式,还有不清楚的同学可以去看一下我的另外一篇文章:
同时我们也知道,vue2.x通过defineProperty方法只是劫持了对象,但是对于数组的处理却是通过重写原生方法实现的响应式,那为什么会这样呐?
现在很多的文章都是说defineProperty存在有缺陷,没有办法监听数组的变化,但实际上defineProperty是可以通过数组下标来实现劫持的,毕竟数组对象是一家嘛,下面就是我做的一点验证:
const arr = ['a','b','c','d'];
function defineReactive(data, key) {
Object.defineProperty(data, key, {
get: function() {
console.log('key:' + key)
},
set: function(value) {
console.log('value:' + value)
}
});
};
function Observe(data) {
Object.keys(data).forEach(function(key) {
defineReactive(data, key, data[key])
})
};
Observe(arr);
arr[1];
arr[2] = '3';
控制台输出如下:
所以说defineProperty本身是可以监控到数组下标的变化的,只是Vue 从通过对性能/体验的性价比考虑放弃了这个特性,defineProperty简直委屈死了。
关于defineProperty实现劫持为什么在性能和体验上不如重写数组方法也有人在github上问过vue的开发者,但是尤雨溪的回答属实太过精炼而我也不知道怎么去比较两者的性能,所以只能硬记了
同样的vue3以上的版本是用了proxy替换了defineProperty,那这又是为什么类?
其实最大的好处就是proxy是对整个对象进行代理,所以可以监听对象某个属性值的变化,还可以监听对象属性的新增和删除,而且还可以监听数组;而 defineProperty 只是给对象的某个已存在的属性添加对应的 getter 和 setter,所以它只能监听这个属性值的变化,而不能去监听对象属性的新增和删除。
但是还有一些文章说还有一部分原因是 proxy在性能上比defineProperty好。可proxy真的比defineProperty性能更好速度更快吗?其实不然,实际上 Proxy 在性能上是要比 Object.defineProperty 差的,详情可以参考 Thoughts on ES6 Proxies Performance 这篇文章,也可以参考掘金博主黄轶大佬的 repo。
总结下来就是defineProperty还是挺好一个方法了,还有就是纸上得来终觉浅,觉知此事要躬行。一定要多看多实践,要有自己的理解和认知,加油!!
欢迎关注公众号:廿九前端营地
可以获取前端资源、大厂外企内推或者联系我一起学习吹水
Tipes:往期精选
「Vue系列」之面试官问NextTick是想考察什么?
「Vue系列」之为什么用Proxy取代Object.defineProperty?
「Vue系列」之Vue3生命周期和新增setup的一些总结
「Vue系列」之Vue3初尝试Cannot find module ‘worker_threads‘报错
「Vue系列」之重新探索v-if和v-show
「Vue系列」之Vue2的数据劫持、发布订阅者模式、diff算法
「Vue系列」之Vue2实现当前组件重新加载