Proxy 是 JavaScript 中用于拦截并自定义对象基本操作的代理构造函数,支持 get、set、has、deleteProperty、apply、construct、ownKeys、defineProperty、getOwnPropertyDescriptor 等拦截;它仅代理第一层属性,无法拦截私有字段、底层内存操作及部分数组内部方法。

JavaScript 中的 Proxy 是一个内置构造函数,用于创建一个代理对象,从而拦截并自定义对目标对象的基本操作(如读取、赋值、函数调用等)。它不是“替代”对象,而是“包裹”对象,让开发者能在访问或修改对象时插入逻辑。
Proxy 能拦截哪些操作?
Proxy 通过 handler(处理器)对象定义拦截行为,每个拦截方法对应一种对象操作。常用且高频的拦截包括:
-
get:读取属性时触发(
obj.prop、obj['key']) -
set:设置属性时触发(
obj.prop = value),可控制是否允许赋值、做数据校验 -
has:使用
in操作符时触发('prop' in obj) -
deleteProperty:调用
delete obj.prop时触发 -
apply:代理目标为函数时,调用该函数触发(
proxy(...args)) -
construct:用
new proxy(...)实例化时触发 -
ownKeys:执行
Object.getOwnPropertyNames()、Object.keys()或for...in循环前触发,可过滤/添加键名 -
defineProperty:调用
Object.defineProperty()时触发 -
getOwnPropertyDescriptor:调用
Object.getOwnPropertyDescriptor()时触发
一个实用的 set + get 拦截示例
常用于响应式系统(如简易 Vue 响应式原理):
const data = { count: 0 };
const handler = {
get(target, key) {
console.log(`读取 ${key}`);
return target[key];
},
set(target, key, value) {
console.log(`设置 ${key} = ${value}`);
target[key] = value;
// 这里可以触发更新视图
updateView();
return true;
}
};
const proxy = new Proxy(data, handler);
proxy.count++; // 输出:读取 count → 设置 count = 1
注意几个关键细节
- Proxy 只代理第一层属性,嵌套对象需递归代理(或结合 Reflect 使用)
- 拦截方法中建议用
Reflect.get()/Reflect.set()替代直接访问,保持默认行为并避免陷阱 - handler 中的 this 指向 handler 对象,不是 proxy 也不是 target
- 被代理的对象无法通过
===与原对象相等(proxy !== data) - 某些操作(如
Object.isExtensible(proxy))会直接作用于 target,除非显式在 handler 中拦截
Proxy 不是万能的 —— 它不能拦截什么?
以下操作无法被 Proxy 直接拦截:
立即学习“Java免费学习笔记(深入)”;
- 对象自有属性的访问(不走原型链)本身不会触发
get,但只要用了proxy.xxx就一定会进get;真正无法拦截的是底层内存操作或引擎内部行为 - 直接读写原型(
obj.__proto__)—— 已废弃,且不推荐;应使用Object.getPrototypeOf()等 API,这些可被对应 trap 拦截 - 数组的
length属性变更、索引越界赋值(如arr[100] = 1)会被set拦截,但部分数组方法(push、pop)内部行为较复杂,需配合get拦截其方法访问再包装 - 私有字段(
#field)无法被 Proxy 观察,这是语言层面限制










