避免副作用最直接有效的方式是创建新数组而非修改原数组,需切断引用关系、不触碰原始数据,优先选用map/filter/concat等返回新数组的方法,慎用push/splice等原地操作。
创建新数组而不是修改原数组,是避免副作用最直接有效的方式。核心在于切断引用关系、不触碰原始数据、让每次操作都可预测可测试。
JavaScript 数组有两类方法:一类直接改原数组(如 push、pop、splice、reverse、sort、fill),另一类返回新数组(如 map、filter、concat、slice、flatMap)。只要目标是“生成结果”,就应优先选后者。
arr.push(item),改用 [...arr, item] 或 arr.concat(item)
arr.splice(i, 1),改用 arr.filter((_, idx) => idx !== i)
arr.reverse(),改用 [...arr].reverse() 或 arr.slice().reverse()
arr.sort(),改用 [...arr].sort((a, b) => a - b)
浅拷贝只断开第一层引用,适合纯值数组或你确定内部对象不会被意外修改的场景;若数组含对象、日期、嵌套数组等,浅拷贝后仍共用内部引用,此时需深拷贝。
[...arr]、arr.slice()、Array.from(arr) 即可[...arr] 只复制对象引用,修改 newArr[0].name 仍会影响原对象structuredClone(arr)(现代环境)、JSON.parse(JSON.stringify(arr))(简单结构,不含函数/undefined/Symbol)硬编码数组(如 const list = [{id: 1}, {id: 2}])会让测试难以覆盖边界情况。把创建过程变成函数,输入决定输出,副作用自然消失。
立即学习“Java免费学习笔记(深入)”;
localStorage、不调用 Date.now()、不发起请求function createItems(count, type = 'default') { return Array.from({ length: count }, (_, i) => ({ id: i + 1, type })) }
0、1、100 或注入异常字段,完全掌控输入const 只防止变量重新赋值,无法阻止对象内部被改。真正起作用的是“是否新建内存空间”。哪怕用 let,只要每次操作都基于副本,就不会污染原始数据。
const arr = [1,2,3]; arr.push(4); —— 原数组已变const arr = [1,2,3]; const newArr = [...arr, 4]; —— 原数组完好,新数组独立props.items.sort(),先拷贝再处理