javascript数组深度克隆需切断所有层级引用,首选structuredclone()(支持多维数组、date、regexp、循环引用等),旧环境可用递归+weakmap实现,慎用json法,第三方库如lodash可作兜底。

JavaScript 数组的深度克隆,核心是切断所有层级的引用关系,确保嵌套的数组、对象、日期、正则等类型都生成全新实例。不能只复制第一层,也不能依赖会丢失数据的“快捷方式”。
优先用 structuredClone() —— 现代标准方案
这是浏览器和 Node.js(v17.0+)原生支持的 API,基于结构化克隆算法,能正确处理:
- 多维数组、嵌套对象
- Date、RegExp、Map、Set、ArrayBuffer、TypedArray
- 循环引用(自动检测并复用已克隆节点)
- Symbol 属性(保留)
用法极简:
const cloned = structuredClone(originalArray);
⚠️ 注意:不支持函数、undefined、BigInt(部分环境)、DOM 节点;若需这些,得回退到自定义方案。
兼容旧环境?用递归 + WeakMap 实现完整深克隆
当目标环境不支持 structuredClone(如 IE、旧版 Node),或需要控制函数/特殊值行为时,推荐手写递归函数。关键点包括:
- 用
WeakMap记录已克隆对象,防止循环引用导致栈溢出 - 区分
Array.isArray()和普通对象,分别初始化[]或{} - 单独处理
Date、RegExp、Map、Set等内置类型 - 遍历
Object.keys()+Object.getOwnPropertySymbols(),覆盖 Symbol 属性
示例精简版:
function deepClone(arr) {
if (!Array.isArray(arr)) return arr;
const map = new WeakMap();
function clone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (map.has(obj)) return map.get(obj);
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
const cloned = Array.isArray(obj) ? [] : {};
map.set(obj, cloned);
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
cloned[key] = clone(obj[key]);
}
}
Object.getOwnPropertySymbols(obj).forEach(sym => {
cloned[sym] = clone(obj[sym]);
});
return cloned;
}
return clone(arr);
}
慎用 JSON.parse(JSON.stringify()) —— 看似简单,陷阱很多
它只适用于“纯数据”场景(全是数字、字符串、布尔、null、普通对象/数组),一旦遇到以下任一情况就会失败或失真:
- 函数 → 消失
- undefined / Symbol / BigInt → 消失
- Date → 变成 ISO 字符串,不再是 Date 实例
- RegExp → 变成空对象
{} - NaN / Infinity → 变成
null - 循环引用 → 直接报错
TypeError: Converting circular structure to JSON
仅建议用于临时调试或已知结构极度简单的配置数组。
第三方库(如 Lodash)—— 开箱即用但引入体积
_.cloneDeep(array) 是经过大量验证的成熟实现,支持几乎所有 JS 类型,含循环引用、Map/Set、自定义类等。适合中大型项目,但要注意:
- 增加包体积(约 70KB gzip 后)
- 若仅需数组克隆,属于“大炮打蚊子”
- 某些严格 CSP 环境可能限制 eval 类操作(Lodash 内部少量使用)
可用作兜底方案,但新项目优先考虑 structuredClone。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











