深层监控需在 Proxy 的 get 拦截中对对象/数组等可代理类型“懒代理化”递归创建新 Proxy,配合 set/deleteProperty/ownKeys 等拦截实现变更响应,并通过 WeakMap 缓存防重复代理、设深度限制与循环引用检测来规避性能与内存风险。

要实现对象的“深层监控”,核心不是给整个对象加一层 Proxy,而是让每次访问嵌套属性时,自动为下一层值也创建 Proxy——也就是在 get 拦截中动态返回一个带相同拦截逻辑的新 Proxy。这本质上是一种递归代理策略:对象本身是代理,它的每个可代理子值(如对象、数组)在被读取时,也立刻变成代理。
关键在于 get 拦截中的“懒代理化”
Proxy 不会自动递归包装所有嵌套结构,必须手动控制。当访问 obj.a.b.c 时,obj 是代理,obj.a 返回原始值;若想继续监控 b 和 c,就得在 get 中判断返回值是否为对象/数组,并为其再套一层同逻辑的 Proxy。
- 只对 plain object、array、map、set 等可代理类型递归包装,避免包装 Date、RegExp、Promise 等原生对象
- 用 WeakMap 缓存已代理过的对象,防止重复代理和内存泄漏
- 原始值(string、number、boolean、null、undefined)直接返回,不代理
需要拦截的关键操作
仅靠 get 不够,深层监控通常还需响应变更行为:
阿里百炼大模型平台多人共享账号用量统计代理服务。解决公司共用账号时无法区分个人用量的问题。适用场景:1)部署用量统计代理;2)统计多人Token用量和调用次数;3)管理大模型API调用配额。
-
set:捕获赋值,触发更新通知,并对新值做代理化(如果它是对象) -
deleteProperty:捕获删除,触发通知 -
ownKeys和getOwnPropertyDescriptor:确保for...in、Object.keys()等能正确枚举代理后的属性 - 数组方法如
push、pop需通过apply拦截或重写原型方法来追踪
避免无限递归和性能陷阱
递归代理容易引发栈溢出或性能问题,尤其在深嵌套或大对象场景:
- 设置深度限制(例如最多代理 6 层),超过后返回原始值并记录警告
- 跳过循环引用对象(用 WeakMap 记录已访问目标,遇到重复引用直接返回缓存代理)
- 对大型数组避免逐项代理,改用索引访问拦截 + 批量变更通知
- 不代理 JSON 序列化过程(
JSON.stringify会忽略 Proxy 行为),需额外提供toJSON方法
实际使用中的边界注意
Proxy 的递归代理无法覆盖所有 JS 行为:
- 严格相等(
===)比较的是代理对象本身,不是原始目标,要注意测试逻辑 - 函数内部的
this绑定、arguments、箭头函数不受影响 - 某些库(如 Vue 2 的 Object.defineProperty 方案)与 Proxy 不兼容,混用需谨慎
- 代理对象无法被
instanceof正确识别,需在getPrototypeOf或isExtensible中适配










