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

为何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 12:45:10