proxy的本质是操作拦截而非对象增强,它通过handler中的trap函数(如get、set、has、ownkeys等)接管[[get]]、[[set]]等内部方法,仅代理第一层且不支持原始值。

Proxy 的本质是操作拦截,不是对象增强
Proxy 不是对目标对象做“功能扩展”,而是为它套上一层可编程的拦截层。所有对代理对象的操作(比如 obj.prop、obj.prop = val、'prop' in obj、delete obj.prop)都会被引擎转为内部方法调用(如 [[Get]]、[[Set]]、[[HasProperty]]),而 Proxy 通过 handler 中对应的 trap 函数接管这些内部行为。
核心拦截器(traps)决定你能控制什么
每个 trap 对应一类底层操作,常见且实用的包括:
- get(target, prop, receiver):拦截读取。可用于缺省值返回、日志记录、响应式依赖收集
- set(target, prop, value, receiver):拦截赋值。适合数据校验、类型约束、变更通知
- has(target, prop):拦截 in 操作符。可隐藏属性或模拟“逻辑存在性”
- ownKeys(target):拦截 Object.keys()、for...in 等枚举行为。能控制哪些键可见
- deleteProperty(target, prop):拦截 delete。可用于禁止删除、软删除标记
- apply/construct:当代理目标是函数或构造器时,分别拦截调用和 new 实例化
必须理解的三个关键细节
第一,Proxy 只代理第一层:若 target.a 是一个普通对象,访问 proxy.a.x 不会触发外层 get;需在 get 中手动递归代理嵌套对象,并注意循环引用问题。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
第二,基本类型不能作为 target:数字、字符串、布尔等原始值直接传入 new Proxy() 会抛出 TypeError;包装对象(如 new String("x"))虽可代理,但隐式转换后会脱离代理控制。
第三,trap 中推荐用 Reflect 转发默认行为:例如在 set 中写 Reflect.set(target, prop, value, receiver),既语义清晰,又能正确处理 this 绑定与 getter/setter 等边界情况。
真实场景中的典型用法
实际开发中,Proxy 常用于:
- 实现响应式系统(如 Vue 3 的 reactive):在 get 中收集依赖,在 set 中触发更新
- 构建带权限控制的对象:在 has 或 get 中检查当前用户是否有权访问该字段
- 创建调试代理:统一打印所有属性读写,辅助排查数据流问题
- 封装不可变数据结构:set 返回 false 或抛异常,阻止意外修改
- 模拟接口契约:get 返回默认值或 throw 提示,降低下游空值风险
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










