JavaScript 数组深度复制实战:从原理到多种实现方案
JavaScript 中的数组属于引用类型,直接赋值或仅使用 slice、concat 等方法只能实现浅层复制,修改新数组仍会影响原数组。若需彻底隔离数据,必须采用深度复制策略。本文将通过 JSON 序列化、自定义递归函数及 jQuery 工具等方法,展示如何在不同场景下正确实现数组的深度复制。
理解 JavaScript 的引用机制
在 JavaScript 中,变量对数据的存储方式取决于数据类型:
- 基本类型(String, Number, Boolean, Null, Undefined):直接存储在栈内存中,赋值时复制的是值本身。
- 引用类型(Array, Object, Function):存储在堆内存中,变量持有的是指向该对象内存地址的指针。因此,简单的
=赋值操作只会复制指针,导致新旧变量指向同一块内存区域。
浅层复制的局限
许多开发者习惯使用 slice() 或 concat() 来复制数组,例如:
// 浅层复制示例
const original = [1, 2, { nested: true }];
const shallowCopy = original.slice(); // 或 original.concat()
// 验证
shallowCopy[0] = 99;
console.log(original[0]); // 1 (一维基本类型被隔离)
shallowCopy[2].nested = false;
console.log(original[2].nested); // false (嵌套对象依然共享)
虽然这两个方法能创建新的数组实例,但对于包含对象或数组的元素,它们仍然是引用关系。这就是所谓的“浅层复制”。
常用的深度复制方法
第1步:使用 JSON 序列化(适用于纯数据对象)
这是最简洁的代码实现方式,利用 JSON.stringify 将对象转为字符串,再通过 JSON.parse 解析回新对象。
function deepCopyJson(obj) {
return JSON.parse(JSON.stringify(obj));
}
const arr1 = [1, 2, { a: 3 }, function() {}];
const arr2 = deepCopyJson(arr1);
arr2[2].a = 999;
console.log(arr1[2].a); // 3 (完全独立)
console.log(arr2); // [1, 2, {a: 999}, undefined]
注意限制:
- 该方法会忽略值为 undefined、Function 或 Symbol 的属性。
- 无法处理循环引用(Circular Reference),遇到环路会导致报错。
第2步:手动递归实现(最通用的原生方案)
为了支持所有类型且不丢失数据,通常需要编写一个递归函数。以下是一个基础的深度克隆实现:
function deepClone(target) {
// 如果不是对象,直接返回
if (typeof target !== 'object' || target === null) {
return target;
}
const clone = Array.isArray(target) ? [] : {};
for (let key in target) {
if (target.hasOwnProperty(key)) {
clone[key] = deepClone(target[key]);
}
}
return clone;
}
优化建议:
生产环境中建议使用成熟库如 Lodash 的 _cloneDeep,因为手写版本很难完美处理 Date、RegExp、Error 等特定内置对象的特殊状态及循环引用问题。
第3步:使用库工具简化流程
如果在项目中使用 jQuery,可以利用其提供的扩展方法。注意第一个参数设为 true 以启用深度模式:
const arr1 = [1, 2, { a: 5 }];
const arr2 = $.extend(true, [], arr1);
arr2[2].a = 888;
console.log(arr1[2].a); // 5
如果使用现代浏览器或 Node.js 环境,还可以结合结构化克隆算法的思路,但需注意标准 structuredClone API 目前已在主流环境得到支持,是实现深度复制的最佳原生选择:
const arr1 = [1, 2, { a: 5 }];
const arr2 = structuredClone(arr1);
arr2[2].a = 888;
console.log(arr1[2].a); // 5
如何选择适合你的方案?
| 方案 | 优点 | 缺点/风险 |
|---|---|---|
| JSON 序列化 | 代码极少,无需依赖 | 丢失函数/undefined,不支持循环引用 |
| 递归函数 | 灵活可控,无依赖 | 需自行处理循环引用和复杂类型,易出错 |
| Lodash / jQuery | 稳定可靠,兼容性好 | 增加包体积 |
| structuredClone | 原生支持,性能较好 | 旧版浏览器可能不兼容 |
以上就是 JavaScript 数组深度复制的详细解析与多种实现方案对比,更多关于 JavaScript 基础语法优化的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













