
本文详解 const arr2 = arr1(引用赋值)与 const arr2 = [...arr1](浅拷贝)的本质差异,通过代码对比阐明二者在内存模型、修改影响及嵌套结构处理上的关键区别。
本文详解 `const arr2 = arr1`(引用赋值)与 `const arr2 = [...arr1]`(浅拷贝)的本质差异,通过代码对比阐明二者在内存模型、修改影响及嵌套结构处理上的关键区别。
在 JavaScript 中,将一个数组赋值给另一个变量时,看似相似的两种写法——直接赋值(arr2 = arr1)和使用扩展运算符展开(arr2 = [...arr1])——实则代表完全不同的内存操作机制:前者是引用共享,后者是浅层拷贝。理解这一区别对避免意外的数据污染、实现安全的状态管理(如 React 中的不可变更新)至关重要。
引用赋值:两个变量指向同一数组对象
当执行 const arr2 = arr1 时,JavaScript 并未创建新数组,而是将 arr1 所指向的内存地址复制给 arr2。这意味着 arr1 和 arr2 是同一数组对象的两个别名:
const arr1 = [1, 2, 3]; const arr2 = arr1; // 引用赋值 console.log(arr1 === arr2); // true —— 严格相等(同一对象) arr2.push(4); console.log(arr1); // [1, 2, 3, 4] —— arr1 同步被修改
任何对 arr2 的增删改操作,都会直接影响 arr1,因为它们操作的是堆内存中的同一个数组实例。
展开运算符:创建新数组(浅拷贝)
而 const arr2 = [...arr1] 利用扩展运算符(...)对 arr1 进行浅拷贝:它新建一个数组,并将 arr1 中每个第一层级元素的值(或引用)依次复制过去:
立即学习“Java免费学习笔记(深入)”;
const arr1 = [1, 2, 3]; const arr2 = [...arr1]; // 浅拷贝 console.log(arr1 === arr2); // false —— 不同对象 arr2[0] = 9; console.log(arr1[0]); // 1 —— 未受影响 console.log(arr2[0]); // 9
此时 arr1 与 arr2 是独立的数组对象,修改彼此不会相互干扰——但仅限于第一层。
浅拷贝的局限性:嵌套对象仍共享引用
浅拷贝不递归复制嵌套结构。若原数组包含对象、函数或另一层数组,这些嵌套值仍以引用形式被“拷贝”,即新旧数组中对应位置指向同一深层对象:
const arr1 = [1, 2, [5, 6]]; const arr2 = [...arr1]; // 浅拷贝 console.log(arr1[2] === arr2[2]); // true —— 子数组引用相同 arr2[2][0] = 9; console.log(arr1[2][0]); // 9 —— arr1 的子数组也被修改!
这正是浅拷贝(Shallow Copy)与深拷贝(Deep Copy)的核心分界点。如需完全隔离嵌套数据,应使用 structuredClone()(现代环境)、JSON.parse(JSON.stringify())(仅限纯 JSON 数据)或第三方库(如 Lodash 的 _.cloneDeep)。
实践建议与总结
- ✅ 需要独立副本且无嵌套结构? → 优先使用 [...arr] 或 arr.slice()、Array.from(arr)。
- ✅ 需修改副本但不影响原始数据? → 必须使用浅拷贝(避免引用赋值)。
- ⚠️ 数组含对象、日期、正则或深层嵌套? → 浅拷贝不够,务必升级为深拷贝方案。
- ❌ 禁止直接赋值后修改副本:const newArr = oldArr; newArr.push(...) 会污染原始数据,属常见副作用陷阱。
一句话牢记:arr2 = arr1 是“同一个人换了个名字”,arr2 = [...arr1] 是“克隆了一个长得一模一样的双胞胎(但双胞胎的孩子还是同一个人)”。 精准选择拷贝策略,是编写健壮、可预测 JavaScript 代码的基本功。










