Proxy是JavaScript中唯一能真正拦截并重写基本操作的机制,通过trap函数接管[[Get]]、[[Set]]等内部方法,需用new Proxy(target, handler)创建,无法代理原始值且仅代理第一层。

Proxy 不是语法糖,也不是对象增强工具,它是 JavaScript 中唯一能真正拦截并重写基本操作(如读取、赋值、in、delete)的机制。
Proxy 的核心作用:拦截对象的底层操作
当你对一个对象做 obj.prop、obj.prop = value、prop in obj、delete obj.prop 或 Object.keys(obj) 这类操作时,JavaScript 引擎会触发对应的内部方法(如 [[Get]]、[[Set]]、[[HasProperty]])。Proxy 就是通过 trap(陷阱)函数把这些内部方法的调用接管过来。
关键点:
- 必须用
new Proxy(target, handler)创建新对象,不能直接修改原对象行为 -
target可以是普通对象、数组、函数甚至null(但多数 trap 会报错) -
handler是一个普通对象,键名是 trap 名(如get、set、has),值是对应函数 - 没定义的 trap 会默认转发到 target,不会自动“透传”——这点常被忽略
最常用的 get 和 set 陷阱怎么写
get 和 set 是使用频率最高的两个 trap,但它们的参数和返回值有明确约定,写错会导致静默失败或无限递归。
立即学习“Java免费学习笔记(深入)”;
常见错误:
- 在
get中直接访问target[prop]而不通过Reflect.get(),可能绕过其他 trap 或丢失 receiver - 在
set中忘记返回布尔值(必须返回true表示成功,否则严格模式下抛TypeError) - 误以为
set的第三个参数receiver总是 proxy 本身——它可能是继承链上的子对象
正确写法示例:
const obj = { count: 0 };
const proxy = new Proxy(obj, {
get(target, prop, receiver) {
console.log('读取', prop);
return Reflect.get(target, prop, receiver);
},
set(target, prop, value, receiver) {
console.log('设置', prop, '为', value);
return Reflect.set(target, prop, value, receiver); // 必须返回 boolean
}
});
为什么 Object.defineProperty 做不到 Proxy 的事
Object.defineProperty 只能监听**已存在的属性**的读写,且无法拦截 in、delete、for...in、Object.keys()、构造函数调用等行为。
而 Proxy 的 trap 覆盖更广:
-
has拦截prop in proxy -
deleteProperty拦截delete proxy.prop -
ownKeys拦截Object.getOwnPropertyNames()、for...in -
apply和construct分别拦截函数调用和new调用 -
getOwnPropertyDescriptor控制Object.getOwnPropertyDescriptor()返回值
注意:ownKeys 返回的必须是数组,且需包含所有 enumerable 为 true 的自有属性(否则 for...in 行为可能异常)。
Proxy 的实际限制和易踩坑点
Proxy 很强大,但不是万能的,几个关键限制常被低估:
- Proxy 对象无法被
===或==与原对象比较相等(它们是不同对象) - 无法代理
undefined、primitive(如字符串、数字),只能代理对象 - 一旦创建,handler 无法被替换;想改行为只能新建 Proxy
- 某些内置方法(如
Array.prototype.push)内部不走标准 [[Set]],而是直接操作索引,导致settrap 可能不触发 - 性能开销明显,尤其高频操作(如循环中大量读写)应谨慎使用
最常被忽略的一点:Proxy 只代理第一层。如果 proxy.nested 是个普通对象,它的操作不会被自动拦截——需要手动递归包装或使用 Proxy.revocable 配合懒代理策略。











