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
相关产品推荐
相关产品推荐

