Proxy 是 JavaScript 中用于拦截和自定义对象基本操作的代理对象,需传入目标对象和处理器对象,支持 get、set 等 13 种陷阱,但无法拦截原型链访问、私有字段及原始值,且未定义的 trap 会透传。

什么是 JavaScript 中的 Proxy 对象
Proxy 是一个包装目标对象的“中间层”,它本身不是新类型的数据,而是一个可配置的拦截器。你创建一个 Proxy 实例时,必须传入一个目标对象(target)和一个处理器对象(handler),后者定义了哪些操作可以被拦截、如何响应。
它的核心价值不是替代对象,而是让你在不修改原始对象的前提下,控制对它的访问行为——比如日志记录、权限校验、响应式更新、数据验证等。
Proxy 能拦截哪些基本操作
ECMAScript 规范定义了 13 种可拦截的“陷阱”(traps),每种对应一种对象操作。常见且高频使用的包括:
-
get:读取属性时触发(obj.prop或obj['prop']) -
set:设置属性时触发(obj.prop = value),可返回false阻止赋值(严格模式下会报错) -
has:使用in操作符时触发('prop' in obj) -
deleteProperty:调用delete obj.prop时触发 -
ownKeys:调用Object.getOwnPropertyNames()、Object.keys()或for...in时触发,可过滤或伪造键名列表 -
defineProperty:调用Object.defineProperty()时触发 -
getOwnPropertyDescriptor:调用Object.getOwnPropertyDescriptor()时触发 -
construct:用new调用代理对象时触发(要求目标必须是函数或类)
其余如 apply(函数调用)、isExtensible、preventExtensions、getPrototypeOf、setPrototypeOf 等也支持,但使用频率较低。
立即学习“Java免费学习笔记(深入)”;
容易忽略的关键限制
Proxy 的拦截能力有明确边界,不是万能的:
- 无法拦截普通对象的原型链访问(比如
obj.toString()不走get,除非该方法定义在obj自身) - 无法拦截私有字段(
#field)的读写,语法层面直接报错,不进入任何 trap - 不能代理非对象(如原始值
string、number),会抛出TypeError -
handler中若未定义某个 trap,对应操作就透传给目标对象,不会自动 fallback 或报错 - 代理对象与原对象是独立引用,修改代理不会自动同步到原对象(除非你在
set中手动同步)
const target = { a: 1 };
const handler = {
get(obj, prop) {
console.log('get:', prop);
return Reflect.get(obj, prop); // 必须显式转发,否则返回 undefined
},
set(obj, prop, value) {
console.log('set:', prop, '=', value);
return Reflect.set(obj, prop, value); // 必须返回布尔值
}
};
const proxy = new Proxy(target, handler);
proxy.a = 2; // 输出 set: a = 2;target.a 变为 2
console.log(proxy.a); // 输出 get: a,然后 2
真正难的不是列出所有 trap,而是判断某次行为是否真的进了你的 get 或 set ——比如 Array.prototype.push 修改的是 length 和索引数字属性,但不触发 set 对 push 方法本身的调用;又比如 Object.assign() 内部用的是底层属性赋值,会触发 set,但你得确保 handler 里正确处理了数值索引或 symbol 键。











