JS中Array.forEach循环内外push到父作用域的数组值不一致问题
问题原因
这个现象和作用域无关,核心是对象引用共享和Object.assign的使用错误导致的。
你通过priceListIndex.find()拿到的rule是priceListIndex数组中原有对象的引用,整个代码运行过程中,同一个columnIndex匹配到的始终是内存里同一个对象。
错误点定位
出错的是这行代码:
rules[sku].push(Object.assign(rule, { price }));
Object.assign的第一个参数是目标对象,你直接传入原rule对象作为目标,相当于每次匹配到同一个规则时,都直接修改这个原对象的price属性。而你push到rules[sku]数组里的,就是这个原对象的引用,所以所有sku下指向同一个规则的条目,最终都会共享最后一次赋值的price值。
对应到你的测试用例:
- 先匹配FOO的第2列,修改
columnIndex=2的原规则price为1,push引用 - 再匹配FOO的第3列,修改
columnIndex=3的原规则price为2,push引用 - 再匹配BAR的第2列,修改同一个
columnIndex=2的原规则price为9999.99,push引用 - 最后匹配BAR的第3列,修改同一个
columnIndex=3的原规则price为8888.88,push引用
最终所有引用columnIndex=2规则的条目,price都变成了最后一次赋值的9999.99。
修复方案
只需要给Object.assign传入空对象作为第一个参数,创建全新的对象存储规则+价格,不修改原规则对象即可:
rules[sku].push(Object.assign({}, rule, { price }));
也可以用对象扩展运算符实现相同效果,写法更简洁:
rules[sku].push({ ...rule, price });
修改后每个push到rules里的都是独立的新对象,互不干扰,最终FOO[0].price就会符合预期等于1。
内容的提问来源于stack exchange,提问作者Cameron Hurd
相关产品推荐
相关产品推荐

