Proxy 是 ES6 引入的代理对象,用于拦截并自定义对目标对象的基本操作;最常用 get 拦截属性读取(支持默认值、虚拟属性)、set 拦截赋值(支持校验、格式化、副作用),需通过 new Proxy(target, handler) 创建,推荐结合 Reflect API 保证语义正确。

JavaScript 中的 Proxy 可以让你创建一个代理对象,拦截并自定义对目标对象的基本操作(比如读取、赋值、删除、枚举等)。最常用的是通过 get 和 set 拦截器来控制属性的读取与赋值行为。
基本用法:创建代理对象
使用 new Proxy(target, handler) 创建代理:target 是被代理的原始对象;handler 是一个配置对象,包含各种拦截方法(trap)。
最小完整示例:
const target = { name: 'Alice', age: 30 };
const handler = {
get(obj, prop) {
console.log(`读取属性: ${prop}`);
return Reflect.get(obj, prop);
},
set(obj, prop, value) {
console.log(`设置属性 ${prop} = ${value}`);
return Reflect.set(obj, prop, value);
}
};
const proxy = new Proxy(target, handler);
proxy.name; // 输出:读取属性: name → "Alice"
proxy.age = 31; // 输出:设置属性 age = 31 → true
拦截读取(get):支持默认值、校验、计算属性
get 拦截器接收三个参数:target(目标对象)、prop(属性名)、receiver(代理对象本身,用于正确处理 this)。常用场景包括:
- 访问不存在的属性时返回默认值(避免
undefined) - 对敏感属性做访问日志或权限检查
- 实现“虚拟属性”(如
proxy.fullName动态拼接)
示例:提供默认值 + 虚拟属性
立即学习“Java免费学习笔记(深入)”;
const user = { firstName: 'John', lastName: 'Doe' };
const proxy = new Proxy(user, {
get(target, prop) {
if (prop === 'fullName') {
return `${target.firstName} ${target.lastName}`;
}
return prop in target ? target[prop] : 'N/A';
}
});
console.log(proxy.fullName); // "John Doe"
console.log(proxy.email); // "N/A"
拦截赋值(set):支持数据校验、格式化、响应式触发
set 拦截器接收四个参数:target、prop、value、receiver。必须返回布尔值:true 表示赋值成功,false 或抛出错误表示失败(严格模式下会报错)。
常见用途:
- 限制属性类型(如 age 必须为正整数)
- 自动转换值(如把字符串数字转成数字)
- 触发副作用(如更新视图、通知监听者)
示例:校验 age 并自动修正
const data = { age: 25 };
const proxy = new Proxy(data, {
set(target, prop, value) {
if (prop === 'age') {
if (typeof value !== 'number' || value < 0 || value > 150) {
throw new Error('age 必须是 0–150 之间的数字');
}
console.log(`年龄已更新为 ${value}`);
}
target[prop] = value;
return true;
}
});
proxy.age = 26; // ✅ 正常执行
// proxy.age = -5; // ❌ 抛出错误
注意事项与最佳实践
使用 Reflect API 是推荐做法,它能保持原生语义(比如正确处理原型链、set 的返回值、get 的 this 绑定)。
- 不要直接操作
target[prop],而应优先用Reflect.get(target, prop, receiver)和Reflect.set(target, prop, value, receiver) - 避免在
get/set中无限递归(例如在get里又读取proxy.xxx) - 代理只对**直接访问**生效,对原始对象的操作(
target.prop)不会被拦截 - 数组索引、length、Symbol 属性等同样可被拦截,但需注意陷阱(如
push内部会多次触发set)
不复杂但容易忽略:代理对象是独立的引用,修改代理会影响原对象,但替换代理变量本身不会影响原对象——这是浅层代理,嵌套对象需递归代理或配合 Proxy.revocable 管理生命周期。


















