一.Object.defineProperty
1.基本概念
Object.defineProperty()是ES5提供的一个方法,用于直接在对象上定义新属性或者修改现有属性,并且返回该对象。
2.核心功能
js
Object.defineProperty(obj, prop, descriptor)
- obj: 要在其上定义属性的对象
- prop:要定义或修改属性的名称
- descriptor:将被定义或修改的属性描述符
3.属性描述符类型
(1)数据描述符
js
{
value: any, // 属性值
writable: boolean, // 是否可写
enumberable: boolean, // 是否可枚举
configurable: boolean // 是否可配置
}
(2)存取描述符
js
{
get: function() {}, // 获取属性值
set: function() {}, // 设置属性值
enumberable: boolean,//
configurable: booleab//
}
4.Vue2中的实现
Vue2使用Object.defineProperty()实现数据响应式
js
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
enumberable: true,
configurable: true,
get() {
console.log(`获取${key}: ${value}`)
return val;
},
set(newVal) {
if (newVal === val) return;
console.log(`设置${key}: ${newVal}`);
val = newVal
}
});
}
5.局限性
- 无法检测对象属性的添加或删除
- 数组变异方法需要特殊处理
- 需要递归遍历对象所有属性
二.Proxy
1.基本概念
Proxy 是ES6引入的新特性,用于创建对象的代理,从而实现对基本操作的拦截和自定义。
2.基本语法
js
const proxy = new Proxy(target, handler);
- target: 要包装的目标对象
- handler: 拦截操作对象
3.常用拦截操作
js
const handler = {
get(target, prop, receiver) {}, // 拦截属性读取
set(target, prop, value, receiver) {}, // 拦截属性设置
deleteProperty(target, prop) {}, // 拦截属性删除
has(target, prop) {}, // 拦截in操作符
// ...一共13中拦截操作
}
4.Vue3中的实现
Vue3使用Proxy重构响应式系统:
js
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
console.log(`获取${key}`);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
console.log(`设置${key}: ${value}`);
return Reflect.set(target, key, value, receiver);
}
});
}
5.优势
- 直接监听整个对象而非属性
- 支持数组变化检测
- 13种拦截操作更全面
- 性能更好
三.Proxy和defineProperty的对比
- Proxy拦截操作更全面
- Proxy初始化性能较慢,但后续运行时性能和内存占用都较低,defineProperty相反
- Proxy不兼容IE浏览器
- Proxy能够监听数组变化