JavaScript深拷贝需创建完全独立的新对象,常用方法有:JSON.parse(JSON.stringify())(限制多)、structuredClone()(现代推荐)、手写递归(灵活可控)、Lodash的_.cloneDeep()(生产稳妥)。

JavaScript 中实现深拷贝,核心是创建一个与原对象完全独立的新对象,所有嵌套层级的属性都复制一份,修改新对象不会影响原对象。最直接的方式不是简单赋值或 Object.assign,因为它们只做浅拷贝。
JSON.parse(JSON.stringify()) —— 快速但限制多
这是最常被用到的“一行深拷贝”写法,适合纯数据对象(仅含字符串、数字、布尔、null、数组、普通对象):
const original = { a: 1, b: [2, 3], c: { d: 4 } };
const copy = JSON.parse(JSON.stringify(original));
⚠️ 常见陷阱:
- 函数、undefined、Symbol 类型会被忽略或丢失
- Date、RegExp、Map、Set、BigInt 等内置对象会变成空对象或报错
- 循环引用(对象内部引用自身)直接抛出异常
- 原型链和 constructor 信息全部丢失
structuredClone() —— 现代浏览器推荐方案
ES2022 引入的原生 API,支持更多类型,且能处理循环引用:
立即学习“Java免费学习笔记(深入)”;
const copy = structuredClone(original);
✅ 支持:Date、RegExp、ArrayBuffer、TypedArray、Map、Set、Blob、File、ImageData,以及循环引用。
❌ 不支持:函数、undefined、Symbol、Promise、window 对象等非可序列化值。
注意:Node.js 从 v17.0 开始支持,但需启用 --experimental-structured-cloning;v18.15+ 默认开启。浏览器兼容性需查 CanIUse(Chrome 98+、Firefox 94+、Safari 15.4+)。
手写递归深拷贝 —— 灵活可控但需谨慎
适用于需要自定义行为(如过滤字段、处理特殊类型、保留原型)的场景。关键点:
- 先判断是否为 null 或基本类型,直接返回
- 区分 Array、Date、RegExp、Map、Set 等类型,分别处理
- 用 WeakMap 记录已拷贝的对象,避免循环引用死循环
- 对普通对象遍历 ownKeys(含 Symbol),递归拷贝每个 value
示例简化版(不含 Map/Set/Date 等扩展):
function deepClone(obj, map = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (map.has(obj)) return map.get(obj);
const clone = Array.isArray(obj) ? [] : {};
map.set(obj, clone);
for (const key of Reflect.ownKeys(obj)) {
clone[key] = deepClone(obj[key], map);
}
return clone;
}
第三方库 —— 生产环境稳妥选择
Lodash 的 _.cloneDeep() 是最成熟的选择,覆盖几乎所有边界情况,包括函数(只拷贝引用)、正则、日期、Map/Set、不可枚举属性、循环引用等。
使用前安装:npm install lodash,然后:
import { cloneDeep } from 'lodash';
const copy = cloneDeep(original);
优点是稳定、文档全、社区验证充分;缺点是增加包体积(若项目极轻量,可考虑按需引入或精简版工具函数)。
不复杂但容易忽略:深拷贝永远有成本,嵌套越深、数据越大,性能开销越明显。实际开发中优先问自己——真的需要深拷贝吗?有时用不可变更新(如 Immer)或设计上避免突变更高效。











