为何使用Reducer函数时会mutate原数组sourceArr?如何避免?
问题描述
我在浏览器Window作用域中存储了对象数组变量sourceArr,尝试通过Reducer函数筛选出特定对象并修改属性以生成refined_data对象,但发现修改操作不仅改变了refined_data,还修改了sourceArr中对应的对象。请问该行为的原因是什么?如何在不修改sourceArr的情况下得到目标refined_data对象?
代码示例:
var dataSeeker = setInterval(() => { if (window.sourceArr) { clearInterval(dataSeeker) let newArr = sourceArr.filter(data => current_case === data.case_id) let refined_data = newArr.reduce((acc, case_data) => { case_data.appointment = 'DD/MM/YYYY - hh:mm:ss A' case_data.name = 'Name' return case_data }, {}) } }, 500)
问题原因与解决方案
原因
JavaScript里对象属于引用类型,filter方法返回的新数组newArr里的元素,并不是原sourceArr中对象的独立副本,而是直接指向原对象的内存地址。所以你在reduce里修改case_data的属性时,其实就是在修改原sourceArr中对应对象的属性,自然会导致原数组被改动。
解决方法
要避免修改原数组,核心是先创建原对象的浅拷贝,再修改拷贝后的新对象,这样操作的就是独立的新对象,不会影响原数组。常用的浅拷贝方式有三种:
- 对象扩展运算符
{...obj} Object.assign({}, obj)- 对象解构赋值
修改后的代码示例:
var dataSeeker = setInterval(() => { if (window.sourceArr) { clearInterval(dataSeeker) let newArr = sourceArr.filter(data => current_case === data.case_id) let refined_data = newArr.reduce((acc, case_data) => { // 先拷贝原对象,生成独立的新对象 const copiedData = { ...case_data }; // 修改新对象的属性 copiedData.appointment = 'DD/MM/YYYY - hh:mm:ss A'; copiedData.name = 'Name'; return copiedData; }, {}) } }, 500)
如果原对象中包含嵌套的子对象(同样是引用类型),浅拷贝无法完全隔离,这时需要用深拷贝,比如自己实现递归深拷贝,或者使用JSON.parse(JSON.stringify(obj))(注意这种方式会忽略函数、undefined等特殊类型)。
内容的提问来源于stack exchange,提问作者lynx_dev
相关产品推荐
相关产品推荐

