Proxy 深度代理数组需拦截变异与非变异方法并返回代理对象,递归代理嵌套结构,用 WeakMap 缓存防重复,支持负索引与稀疏数组,保持原型链和 this 正确性。

Proxy 对数组方法做深度拦截,关键不是只代理数组本身,而是让所有可能产生新对象的操作(比如 push 返回的新数组、map 生成的新数组、甚至嵌套对象里的数组)也自动被代理。单纯拦截 get 只能捕获方法调用,但无法保证后续链式操作仍处于代理控制下。
拦截变异方法并返回代理数组
数组的 push、pop、splice 等方法会直接修改原数组,需在 get 中识别这些方法名,并返回包装函数——该函数执行原始操作后,确保返回值(如 splice 返回的删减项数组)也被代理。
- 对返回数组的方法(如
slice、filter、map),需检查返回值是否为数组,是则用相同 handler 再包一层 - 包装函数内部必须用
Reflect.apply调用原方法,避免丢失this绑定 - 不要硬编码方法列表,可用
Array.prototype上的可枚举方法动态判断
递归代理嵌套结构中的数组
当数组元素本身是对象或含数组时(如 arr[0] = { list: [1,2] }),仅代理外层数组不够。必须在 get 拦截中判断返回值:若为数组或纯对象,就递归创建新 Proxy。
- 使用
WeakMap缓存已代理过的数组/对象,防止重复代理和循环引用问题 - 跳过
null、undefined、基本类型、内置实例(如Date、RegExp),避免代理失败 - 对
length属性不做特殊处理,它由数组内部自动维护;重点是拦截会改变它的方法调用
支持负索引与稀疏数组行为
原生数组不支持 arr[-1],但可通过 get 拦截实现“魔法索引”。同时需兼容稀疏数组(如 [1,,3])的 in 判断和遍历逻辑。
立即学习“Java免费学习笔记(深入)”;
- 在
get中检测prop是否为负整数字符串(如"-2"),转成正向索引target.length + Number(prop) - 重写
has拦截器,使-1 in proxyArr返回正确布尔值 -
ownKeys需返回所有数字索引(包括空位),否则for...in或Object.keys会漏掉稀疏项
保持原型链与方法上下文正确
代理后的数组仍要能正常使用 instanceof Array、调用 .forEach 等,且方法内 this 必须指向代理对象本身,而非原始数组。
- 所有包装函数调用时,用
.apply(proxy, args)或Reflect.apply(method, proxy, args)绑定this - 避免在 handler 中直接访问
target[prop],一律通过Reflect.get/Reflect.set并传入receiver参数 - 不覆盖
constructor和__proto__,让proxy instanceof Array仍为true


















