concat可实现数组浅拷贝,因其返回新数组且不修改原数组,对基本类型复制值、引用类型仅复制地址;常与slice()、展开运算符并用,但无法深拷贝对象。

JavaScript 中用 concat 实现浅拷贝,本质是利用它“返回新数组、不改原数组”的特性,顺带完成一次一层结构的复制。它不是专为拷贝设计的方法,但因行为可靠、语法简洁,常被当作数组浅拷贝的快捷手段。
concat 为什么能当浅拷贝用
因为 concat() 调用时不传参,就等价于把原数组所有元素依次“取出来再装进一个新数组”:
- 对基本类型(数字、字符串、布尔值、null、undefined)——真正复制值,新旧数组互不影响
- 对引用类型(对象、嵌套数组)——只复制内存地址,新旧数组中对应位置仍指向同一块堆内存
- 原数组完全不变,符合不可变操作习惯,适合函数式编程场景
常见写法与对比
以下三种方式效果一致,都生成一个浅拷贝数组:
-
arr.concat()—— 最常用,语义清晰 -
arr.slice()—— 同样不传参,从头到尾截取 -
[...arr]—— 展开运算符,ES6 写法,可读性更强
例如:
let copy = original.concat();
copy[0] = 99; // ✅ 原数组不受影响
copy[2].x = 999; // ❌ 原数组的 {x: 10} 也会变成 {x: 999}
拼接 + 浅拷贝一步到位
如果你既要合并数组、又要确保不污染原数据,concat 天然支持边拼接边拷贝:
- 直接拼接多个数组:
arr1.concat(arr2, arr3)→ 返回全新数组,三者都不变 - 混搭值和数组:
arr.concat(99, [4,5], 'end')→ 所有参数被展开后追加 - 想“先拷一份再拼”?不需要两步:
arr.concat()本身已新建数组,后续拼接自然基于副本
比如备份并扩展配置项:
const base = [{id: 1}, {id: 2}];const extended = base.concat({id: 3}, {id: 4});
// extended 是新数组,base 不受影响;但所有对象仍是共享引用
什么时候要小心 concat 的“浅”
只要数组里含有对象、数组、函数、正则等引用类型,修改它们内部属性就会波及原数组:
- ✅ 安全操作:替换整个元素(
copy[i] = newValue)、增删元素(push/pop) - ❌ 危险操作:修改对象属性(
copy[0].name = 'xxx')、修改子数组项(copy[1][0] = 99) - ⚠️ 提示:若需彻底隔离,应选
JSON.parse(JSON.stringify(arr))(简单场景)、structuredClone()(现代环境)或专用库如 Lodash 的cloneDeep
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











