深度代理通过get拦截对嵌套对象“懒代理”实现:访问时递归用Proxy包裹对象,WeakMap缓存防重复;set时对新对象值再代理;需透出Date/RegExp等内置对象,避免代理全局对象。

Proxy 本身只代理一层,要实现深度代理嵌套,核心思路是:在 get 拦截中对返回的属性值做“懒代理”——只有访问到嵌套对象时,才递归用 Proxy 包裹它。
递归代理:每次 get 返回新 Proxy
关键在于不让原始嵌套对象暴露出去。只要某个属性值是对象(包括数组、函数等),就用同样的 handler 再包一层。
- 判断返回值是否为对象且非 null,再用
new Proxy(value, handler)包装 - 避免重复代理:可加缓存(WeakMap)记录已代理过的对象,防止无限循环或内存泄漏
- 注意数组方法(如
push、map)返回的新数组也要被代理,否则链式调用会断层
处理 set 和 delete:保持响应式语义
set 拦截不仅要赋值,还要对新值做代理;deleteProperty 需触发依赖更新(如果用于响应式系统)。
- 赋值时若新值是对象,先代理再设入目标
- 删除属性后应通知监听者(如 Vue 的
trigger或自定义事件) - 对
in操作符、Object.keys()等需重写ownKeys和has
避开陷阱:null、Date、RegExp、内置构造器
不是所有对象都适合代理。原始类型(string/number/boolean)直接返回;Date、RegExp、Promise 等内置对象代理后行为异常,应原样透出。
立即学习“Java免费学习笔记(深入)”;
- 用
Object.prototype.toString.call(val)精准判断类型 - 对
val instanceof Date或val instanceof RegExp直接返回原值 - 避免代理 window、document 等全局对象(会报错或引发安全限制)
简易可运行示例
下面是一个最小可用的深度代理工厂:
function deepProxy(obj, handler = {}) {
const proxied = new WeakMap();
const baseHandler = {
get(target, key, receiver) {
const val = Reflect.get(target, key, receiver);
if (val !== null && typeof val === 'object') {
if (!proxied.has(val)) {
proxied.set(val, new Proxy(val, baseHandler));
}
return proxied.get(val);
}
return val;
},
set(target, key, value, receiver) {
if (value !== null && typeof value === 'object') {
value = deepProxy(value);
}
return Reflect.set(target, key, value, receiver);
},
...handler
};
return new Proxy(obj, baseHandler);
}
调用 deepProxy({ a: { b: { c: 1 } } }) 后,proxy.a.b.c 修改会触发对应层级的 set,且 proxy.a.b 本身也是代理对象。


















