You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript中调用Array.push()为何无法触发Proxy的set陷阱?

为什么Proxy的set陷阱在数组push时不触发?

嘿,这个问题我之前踩过坑!其实核心原因是Proxy的set陷阱只在直接给对象的属性赋值时才会触发,而你调用proxObj.fooArray.push(val)的操作,并没有修改proxObj上的fooArray属性本身——你只是先拿到了fooArray对应的原数组,然后调用数组自己的push方法去修改数组内部的元素,这时候修改的是数组的索引和length,不是给proxObj.fooArray重新赋值,所以原Proxy的set陷阱根本不会被触发。

解决方案:给数组也套一层Proxy

要监听数组内部的变化,我们可以在Proxy的get陷阱里做判断:如果访问的属性是数组,就给这个数组也套一层Proxy,这样数组内部的修改(比如push、splice、直接改索引)都会触发新Proxy的set陷阱。

修改后的代码如下:

let input = document.querySelector('input')
input.addEventListener('change', e => {
  let val = e.target.value
  proxObj.foo = val
  proxObj.fooArray.push(val)
})
let obj = {
  foo: "bar", // 会打印:foo mutated to 对应值
  fooArray: [] // 现在数组元素变化也会打印日志了
}

proxObj = new Proxy(obj, {
  // 先拦截属性的获取
  get: (target, prop) => {
    const value = target[prop];
    // 如果获取的是数组,返回代理后的数组
    if (Array.isArray(value)) {
      return new Proxy(value, {
        set: (arrTarget, arrProp, arrVal) => {
          console.log(`fooArray[${arrProp}] mutated to`, arrVal);
          arrTarget[arrProp] = arrVal;
          return true; // 必须返回true,表示赋值成功
        }
      });
    }
    return value;
  },
  set: (target, prop, val) => {
    console.log(prop, "mutated to", val)
    target[prop] = val
    return true; // 这里之前的代码漏了return true,补上避免报错
  }
})

补充说明

  • 原代码里的set陷阱最后漏了return true,这会导致严格模式下抛出错误,所以一定要补上;
  • 如果需要监听更多数组方法(比如pop、shift这类会修改数组的方法),还可以在数组的Proxy里拦截get陷阱,监听这些方法的调用,不过上面的代码已经能覆盖push带来的元素新增和length变化了;
  • 如果你只是想监听数组整体被替换的情况(比如proxObj.fooArray = [1,2,3]),原代码的set陷阱就足够,但要监听内部元素变化,就必须给数组单独套Proxy。

内容的提问来源于stack exchange,提问作者Le Marin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:25:05