WHAT - JavaScript 中 Object.defineProperty() 和 Proxy 对比
目录
- 一、Object.defineProperty()
- 作用
- 基本语法
- 示例:定义一个只读属性
- 示例:定义 getter/setter
- 二、`Proxy`
- 作用
- 基本语法
- 示例:拦截属性访问
- 对比:defineProperty vs Proxy
- 场景选择建议
在 JavaScript 中,Object.defineProperty()
和 Proxy
都可以用来拦截/控制对象的属性访问与修改,但它们适用的场景、能力和语法上有较大差异。
一、Object.defineProperty()
作用
给对象的某个属性定义更精细的特性,比如只读、不可枚举、拦截 getter/setter。
基本语法
Object.defineProperty(obj, 'key', {
get() { return value; },
set(newVal) { value = newVal; },
enumerable: true,
configurable: true
});
示例:定义一个只读属性
const user = {};
Object.defineProperty(user, 'name', {
value: 'Tom',
writable: false // 不可更改
});
user.name = 'Jerry';
console.log(user.name); // Tom
示例:定义 getter/setter
const person = {};
let _age = 18;
Object.defineProperty(person, 'age', {
get() {
console.log('get age');
return _age;
},
set(val) {
console.log('set age:', val);
_age = val;
}
});
person.age = 20; // set age: 20
console.log(person.age); // get age → 20
二、Proxy
作用
创建一个对象的代理,可拦截几乎所有操作(读取、写入、删除、函数调用等)。
基本语法
const proxy = new Proxy(target, {
get(target, prop) {
return target[prop];
},
set(target, prop, value) {
target[prop] = value;
return true;
}
});
示例:拦截属性访问
const user = { name: 'Tom' };
const proxy = new Proxy(user, {
get(target, prop) {
console.log(`读取属性:${prop}`);
return target[prop];
},
set(target, prop, value) {
console.log(`设置属性:${prop} = ${value}`);
target[prop] = value;
return true;
}
});
proxy.name; // 读取属性:name
proxy.age = 30; // 设置属性:age = 30
更多关于 proxy 的内容可以阅读 Proxy 代理和 Reflect API
对比:defineProperty vs Proxy
特性 | Object.defineProperty() | Proxy |
---|---|---|
支持属性拦截 | ✅ 仅能拦截已知属性 | ✅ 所有属性都能动态拦截 |
可拦截类型 | 访问/设置 | 访问、设置、删除、函数调用等(13种 trap) |
是否修改原对象 | ✅ 直接修改原对象 | ❌ 返回一个新的代理对象 |
多层嵌套对象支持 | ❌ 需手动为每一层递归处理 | ✅ 可结合递归实现深层代理 |
Vue2 用于响应式 | ✅ defineProperty 实现响应式 | ❌ |
Vue3 用于响应式 | ❌ | ✅ 使用 Proxy 实现响应式 |
场景选择建议
需求 | 推荐方式 |
---|---|
精准控制某个属性 | Object.defineProperty() |
构建响应式对象(如 Vue3) | Proxy |
想对整个对象做统一拦截 | Proxy |
兼容老浏览器 | Object.defineProperty() (IE9+) |
如果你想自己实现一个响应式系统、双向绑定,或者拦截 API 调用,Proxy
更强大。如果只是限制某个属性或定义只读/计算属性,defineProperty
就足够。