扩展运算符对多维数组仅做第一层浅拷贝,内层数组或对象仍共享内存地址,修改会相互影响;一维数组安全,二维及以上危险;替代方案包括JSON序列化、递归拷贝、Lodash的_.cloneDeep()等。

ES6 扩展运算符([...arr] 或 {...obj})对多维数组只能做**第一层浅拷贝**,无法真正实现深拷贝。它复制的是外层数组的结构,但内部嵌套的数组或对象仍共享同一内存地址——改内层值,原数组和拷贝数组会互相影响。
为什么扩展运算符对多维数组不安全
它只展开一层可迭代结构,对嵌套的引用类型不做递归处理:
-
一维数组(纯基本类型):安全。例如
const arr1 = [1,2,3]; const arr2 = [...arr1];,修改arr2[0]不会影响arr1 -
二维及以上数组(含子数组):危险。例如
const arr1 = [[1,2], [3]]; const arr2 = [...arr1];,此时arr1[0] === arr2[0]为true;若执行arr2[0].push(9),arr1[0]也会变成[1,2,9]
替代方案:可靠实现多维数组深拷贝
根据场景选择合适方法,兼顾兼容性、性能与语义清晰度:
-
JSON 序列化反序列化(简单场景):
JSON.parse(JSON.stringify(arr))。适用于纯数据(无函数、undefined、Date、RegExp、循环引用),代码最简,但有类型丢失风险(如new Date()变成字符串) - 递归拷贝(可控、通用):手动遍历判断类型,对数组/对象递归调用,基础类型直接返回,引用类型新建并深拷贝。适合需要保留特殊类型或自定义逻辑的项目
-
使用成熟工具库(推荐生产环境):如 Lodash 的
_.cloneDeep(),已全面处理 Date、Map、Set、RegExp、TypedArray、循环引用等边界情况,稳定且经过大量验证
小技巧:组合使用避免全量深拷贝
有时不需要完整深拷贝,只需隔离特定层级:
- 对二维数组,可先用扩展运算符拷贝外层,再对每个子项单独深拷贝:
const deepCopy = arr.map(item => Array.isArray(item) ? [...item] : item);(仅适用于单层嵌套) - 配合
structuredClone()(现代浏览器支持):structuredClone(arr)是原生深拷贝 API,支持 Map/Set/Date 等,但暂不支持函数和某些特殊对象,可作为 JSON 方案的升级替代
不复杂但容易忽略:别让“看起来像新数组”的假象掩盖了引用共享的本质。只要涉及嵌套结构,就该主动确认拷贝深度。


















