Proxy比Object.defineProperty到底好在哪?
大家都知道,从 Vue 3 开始,双向绑定机制从 Object.defineProperty
转换成了 Proxy
,但很少有人去问为什么,本着学习前端知识又可以水一篇文章的想法,于是我又开始水了一篇文章。
1. 性能和灵活性
Vue 2 使用
Object.defineProperty
为对象的每个属性定义 getter 和 setter,监控每个属性的变化。但对于嵌套对象,它需要递归地为每层属性进行定义,这会导致性能开销和代码复杂度的增加。因为存在深度遍历,就会存在效率的损失,
而在深度遍历后,对对象进行属性 新增 或者使用 delete 进行删除,delete操作符不会触发set函数)就无法实现响应式。
function isObject(v) {
return typeof v === 'object' && v != null;
}
function observe(obj) {
if (!isObject(obj)) {
return;
}
for (const k in obj) {
let v = obj[k];
if (isObject(v)) {
observe(v);
}
Object.defineProperty(obj, k, {
get() {
console.log(k, '读取', v);
return v;
},
set(val) {
console.log(k, '更改', val);
v = val;
}
})
}
}
const obj = {
name: '小明',
age: 18,
love: {
food: 'apple',
ball: 'basketball'
}
}
observe(obj);
obj.love.food = 3;
delete obj.age; // 不会触发
Vue 3 使用
Proxy
可以直接代理整个对象,自动监听对象内层次嵌套的属性变化,不需要递归地遍历对象的每一层。因此,它对复杂对象的性能优化更加显著。
function isObject(v) {
return typeof v === 'object' && v != null;
}
const obj = {
name: '小明',
age: 18,
love: {
food: 'apple',
ball: 'basketball'
}
}
function observe(obj) {
const proxy = new Proxy(obj, {
get(target, k) {
let v = target[k];
// 读取属性的时候,如果是属性是对象才会再进行监听。
if(isObject(v)) {
v = observe(v);
}
console.log(k, '读取')
return v;
},
set(target, k, v) {
if (target[k] !== v) {
target[k] = v;
console.log(k, '更改')
}
},
deleteProperty(target, k) {
console.log(k, '删除')
delete target[k];
}
})
return proxy;
}
const proxy = observe(obj);
proxy.love.ce = 10;
delete proxy.love.ce;
2. 对新增和删除属性的支持
Object.defineProperty 无法检测到属性的新增或删除,只能在对象定义时设置已存在的属性。Vue 2 通过
Vue.set
和Vue.delete
提供了一种手动侦测新增属性的方式,但这种方法较为繁琐且不是完全自动的。Proxy 可以直接监听对象的新增和删除操作,通过
set
和deleteProperty
拦截器自动响应属性的变化。这样 Vue 3 可以更自然地支持动态属性,提升了响应式的灵活性和简便性。
3. 数组变化的检测
Vue 2 需要用特殊的方式来监控数组的变化(如
push
、pop
等),因为defineProperty
无法直接拦截数组的长度变化或其他方法。Vue 2 中通过重写数组方法来监控数组的变化,但这种做法复杂且影响性能。Proxy 可以直接代理数组对象并捕获其各种操作,无需重写数组方法。它不仅可以侦测到数组内容变化,还可以监控数组的长度变化。这使得 Vue 3 的响应式数组更加高效和直观。
4. 更好的跨平台兼容性
Vue 3 的响应式机制不再依赖特定的属性定义方式,可以在更多平台(如 Web 和移动设备)上有更一致的表现。同时,
Proxy
的 API 在现代 JavaScript 引擎中也有较好的支持度和优化,这使得 Vue 3 的响应式系统更具兼容性和效率。
5. 未来可扩展性
Proxy 能够拦截 13 种不同的操作(如
get
、set
、deleteProperty
、has
、ownKeys
等),Vue 3 只使用了部分功能(主要是get
和set
)来构建响应式数据系统。这种扩展能力使得 Vue 3 的响应式系统未来可以轻松实现更多的功能和优化,比如在调试模式下增加属性访问的日志等。
6. 总结
Vue 3 引入 Proxy
来替代 Object.defineProperty
,解决了 Vue 2 在动态属性、嵌套对象、数组监控等方面的不足,同时减少了性能开销和代码复杂度。Proxy
的使用不仅让 Vue 3 的响应式系统更加高效、灵活,还为未来的功能扩展提供了更多可能性。
- 感谢你赐予我前进的力量
本网站的原创文章部分资源内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系博主邮箱:zzyo.yj@outlook.com 进行删除处理
本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向博主举报
声明:版权所有,违者必究 | 如未注明,均为原创 | 本网站采用CC BY-NC-SA 4.0 协议进行授权
转载:转载请注明原文链接 - Lycoris