Proxy 通过 get 拦截器实现虚拟属性:拦截未定义属性访问,按规则动态计算(如 fullName 拼接)、支持函数式调用(如 formatDate)、可缓存结果、需用 Reflect.get 避免递归,并注意内置方法陷阱。

Proxy 可以通过拦截 get 操作,对未定义的属性名执行动态计算逻辑,从而实现“虚拟属性”——即属性本身不真实存在于目标对象,但访问时能按需返回计算结果。
用 get 拦截器捕获未知属性访问
核心是利用 Proxy 的 get(target, prop, receiver) 拦截器。当访问一个 target 上不存在的属性时,不直接返回 undefined,而是判断 prop 是否属于预设的虚拟属性规则(比如以 is 开头、含 Count、或匹配正则),再执行对应计算。
- 先检查
prop in target或Object.prototype.hasOwnProperty.call(target, prop)判断是否为真实属性 - 若不是,进入虚拟逻辑:例如
user.fullName可拼接firstName和lastName - 注意使用
Reflect.get(target, prop, receiver)保持原型链和 getter 行为一致
支持带参数的虚拟属性(如方法调用)
纯属性访问无法传参,但可通过返回函数模拟“可调用的虚拟属性”。例如 obj.formatDate('YYYY-MM-DD') 实际是 get 返回一个闭包函数,内部捕获 target 状态并执行计算。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 在
get中识别特定属性名(如formatDate),返回一个绑定上下文的函数 - 函数体内可读取 target 的其他字段(如
date),避免硬编码或额外依赖 - 注意 this 指向:用箭头函数或显式 bind(receiver),确保调用时
this是代理对象
缓存计算结果提升性能
频繁访问同一虚拟属性时,重复计算可能浪费资源。可在 Proxy 内部维护一个 WeakMap 或普通 Map 缓存结果,键为 [target, prop],值为计算结果。
立即学习“Java免费学习笔记(深入)”;
- WeakMap 更适合长期存活的目标对象,避免内存泄漏
- 缓存前需确认计算结果是否纯(无副作用、输入不变则输出不变)
- 若底层数据变化,需配合 observe 或手动清除缓存(例如监听 setter 或提供
invalidate方法)
避免无限递归与陷阱
在 get 中读取 target 属性时,若逻辑不当,可能触发自身拦截,造成死循环。例如在计算 fullName 时又访问 firstName,而该访问又被同一 Proxy 拦截。
- 统一用
Reflect.get(target, key, receiver)代替target[key],确保跳过当前 Proxy 拦截 - 避免在
get中直接读取被代理对象的同名属性(除非明确需要递归逻辑) - 对
toString、valueOf等内置方法访问要小心,它们常被隐式调用,可能意外触发虚拟逻辑

















