Proxy 代理数组需手动拦截索引赋值和 length 修改:在 set trap 中识别数字字符串索引并验证合法性,对 length 变更模拟截断/扩展行为,同时包装 push/pop/splice 等方法以确保语义正确与事件通知。

Proxy 代理数组本身无法直接侦听索引赋值(如 arr[0] = 1)或 length 修改(如 arr.length = 0)——因为这些操作触发的是 set trap,而标准数组的索引访问和 length 设置属于“可配置但不可拦截的内部行为”,除非你主动在 set 中识别并响应它们。
识别并拦截索引写入(如 arr[i] = x)
数组的数字索引(如 '0'、'12')在 JavaScript 中是字符串属性名。只要该属性名满足 toString(Number(prop)) === prop 且 Number(prop) >= 0,就可视为有效数组索引。在 set trap 中做此判断,即可捕获索引变更:
- 检查
prop是否为纯数字字符串(例如/^\d+$/.test(prop)) - 验证转换后是否为合法索引:
const idx = Number(prop); if (idx >= 0 && idx === Math.floor(idx)) { /* 是索引 */ } - 若命中,触发自定义回调(如
onIndexSet(idx, value, oldVal)),再执行原操作
拦截 length 修改(如 arr.length = n)
length 是数组的自有属性,修改它会走 set trap。但要注意:设置 length 可能导致元素截断或补 undefined,需手动模拟行为并通知变化:
⚠️ 已弃用 — 该技能已拆分为两个独立技能,以提升模块化程度:**webchat-https-proxy**(HTTPS/WSS 反向代理)和 **webchat-voi...**
- 当
prop === 'length',先保存旧值oldLength = target.length - 若新值
n ,遍历并删除索引 <code>[n, oldLength - 1]对应的项,触发onIndexDelete - 若新值
n > oldLength,新增的索引位置值为undefined,可选择性触发onIndexSet - 最后调用
Reflect.set(target, prop, value, receiver)完成设置
保持数组方法语义正确(push/pop/splice 等)
仅靠 set trap 不足以覆盖所有变更场景。例如 push 内部会同时写入索引 + 修改 length,而 splice 更复杂。稳妥做法是:对常用方法做包装(即“代理方法”):
- 在 Proxy 的
gettrap 中,对push、pop、shift、unshift、splice返回重写的函数 - 每个包装函数执行原方法后,显式调用
onLengthChange或批量onIndexSet/onDelete - 例如
push后,新长度为target.length,新增索引范围是[oldLen, oldLen + args.length - 1]
注意边界与性能权衡
完全代理数组行为比代理普通对象更重。实际使用中需权衡监听粒度与开销:
- 避免在
set中对每个属性都做正则或 Number 转换;可先用prop in target或Array.isArray(target) && !isNaN(prop) && prop !== ''快速过滤 -
length截断时,不要用delete target[i](会破坏数组稀疏性),而是设为undefined并触发删除通知 - 若只需响应「最终状态」,可用
Object.defineProperty配合 setter 拦截length,再结合Proxy拦截索引——但无法拦截原生方法内部变更,仍需包装
不复杂但容易忽略:Proxy 数组监听的关键不在“能否代理”,而在“如何把 JS 引擎对数组的特殊处理,映射回可感知的变更事件”。你得自己补全那层语义桥接。

















