proxy 可拦截对象的任意操作,关键在于 handler 中正确设置 trap 方法;它代理访问行为而非拷贝对象,需递归代理嵌套对象并注意 receiver 和循环引用问题。

Proxy 可以拦截对整个对象的任意操作,比如读取、赋值、删除、判断是否存在、遍历等,关键在于正确设置 handler 中的 trap(陷阱)方法。
基础用法:创建一个可拦截的对象代理
Proxy 构造函数接收两个参数:目标对象(target)和处理器对象(handler)。handler 中定义各种拦截方法,每个方法对应一种操作行为。
- 只要在 handler 中实现了某个 trap(如 get、set、has、ownKeys 等),对应的操作就会被拦截
- 未定义的 trap 会直接转发到原对象,不触发拦截
- Proxy 代理的是“访问行为”,不是拷贝对象;所有操作仍作用于原 target(除非 trap 内手动修改)
常用 trap 示例与作用
以下是高频使用的拦截方法及其典型用途:
-
get(target, prop, receiver):拦截属性读取(
obj.x、obj['x']),可用于默认值、响应式依赖收集 -
set(target, prop, value, receiver):拦截属性赋值(
obj.x = 1),可做数据校验、触发更新 -
has(target, prop):拦截
in操作符('x' in obj),控制属性“可见性” -
ownKeys(target):拦截
Object.keys()、for...in、Reflect.ownKeys(),可过滤或添加键名 -
deleteProperty(target, prop):拦截
delete obj.x,可禁止删除或记录日志 -
defineProperty(target, prop, descriptor):拦截
Object.defineProperty()
注意 this 指向与 receiver 参数
在 get/set 中,receiver 是原始调用时的 this(通常是 proxy 本身),用于正确处理原型链上的 getter/setter。若忽略 receiver 直接用 target 访问,可能绕过代理逻辑。
- 推荐写法:
return Reflect.get(target, prop, receiver),保证语义一致且不破坏原型链 - 避免硬编码
target[prop],否则继承自原型的访问不会被拦截
嵌套对象也要代理才能拦截
Proxy 默认只代理第一层。如果属性值是对象,需递归代理或按需代理(例如 Vue 3 的 reactive 就采用“惰性代理”策略)。
- 简单递归方式:在 get 中检测返回值是否为对象,是则返回其 Proxy 版本
- 更高效做法:仅当访问到嵌套对象时再创建代理(避免初始化开销)
- 注意循环引用:需缓存已代理的对象,防止无限递归
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











