JavaScript 数组深度复制实战:从原理到多种实现方案

小鹿同学
小鹿同学
发布时间:2026-10-13 | 4人浏览过
原创

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 基础语法优化的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表