贝利信息

为什么你的 Redux Reducer 函数会意外修改原始数组?

日期:2026-01-06 00:00 / 作者:花韻仙語

javascript 中对象是引用类型,`reduce` 回调中直接修改 `case_data`(即原数组中对象的引用)会导致原始 `sourcearr` 被污染;正确做法是创建新对象而非就地修改。

在你提供的代码中,问题根源在于这行逻辑:

case_data.appointment = 'DD/MM/YYYY - hh:mm:ss A'
case_data.name = 'Name'

虽然 case_data 是 reduce 的当前迭代项,但它并非独立副本,而是 sourceArr 中原始对象的直接引用。因此,对 case_data 属性的赋值操作,实质上是在修改 sourceArr 中对应对象本身——这违反了函数式编程中“不可变性”(immutability)的基本原则,也与 Redux 等状态管理理念背道而驰。

✅ 正确做法:返回全新对象,不触碰原数据

应使用对象展开语法({...case_data, ...newProps})或 Object.assign() 创建浅拷贝,并覆盖指定字段:

let refined_data = newArr.reduce((acc, case_data) => {
  // ✅ 安全:基于原对象创建新对象,不修改 sourceArr
  return {
    ...case_data,
    appointment: 'DD/MM/YYYY - hh:mm:ss A',
    name: 'Name'
  };
}, {});
⚠️ 注意:{...case_data} 仅执行浅拷贝。若 case_data 内部含有嵌套对象(如 case_data.patient.address),仍需深度克隆(可借助 structuredClone() 或 Lodash 的 cloneDeep)。

? 额外优化建议

✅ 总结

错误行为 正确替代
case_data.name = 'X'(直接赋值) return { ...case_data, name: 'X' }(返回新对象)
依赖副作用修改输入 所有变换均通过纯函数返回新数据
忽略嵌套对象的可变性 深度克隆复杂嵌套结构(必要时)

遵循“永不直接修改输入对象”的原则,不仅能避免 sourceArr 被意外污染,更能提升代码可预测性、可测试性与协作友好度。