深拷贝创建完全独立的对象副本,浅拷贝仅复制顶层属性引用;需根据是否修改副本且不影响原对象来选择;structuredClone()是现代推荐方案,但不支持function和undefined。

深拷贝会创建一个全新对象,所有嵌套层级的值都独立复制;浅拷贝只复制第一层属性引用,嵌套对象仍共享内存地址。判断是否需要深拷贝,关键看后续是否要修改副本而不影响原对象。
浅拷贝:只复制对象顶层属性
浅拷贝后,obj1 和 obj2 的顶层属性互不干扰,但若某个属性是对象或数组,它们仍指向同一块内存。
常见实现方式:
-
Object.assign({}, obj)—— 仅适用于普通对象,不处理null、undefined或 Symbol 键 -
{...obj}(展开运算符)—— 同样只作用于可枚举自有属性,无法拷贝原型链或不可枚举属性 -
Array.prototype.slice()或[...arr]—— 对数组有效,但对嵌套数组无效
const a = { x: 1, y: { z: 2 } };
const b = { ...a };
b.y.z = 99;
console.log(a.y.z); // 输出 99 —— 被意外修改了
深拷贝:递归复制所有嵌套层级
深拷贝目标是让副本与原对象彻底隔离。但要注意:不是所有值都能安全深拷贝,比如 function、undefined、Symbol、Date、RegExp、Map、Set 等类型在不同方案中表现不一。
立即学习“Java免费学习笔记(深入)”;
常用方法对比:
-
JSON.parse(JSON.stringify(obj))—— 快速但有严重限制:会丢弃undefined、function、Symbol、Date(变成字符串)、RegExp(变成空对象)、NaN(变成null),且无法处理循环引用 -
structuredClone()(现代浏览器 & Node.js 17.0+)—— 原生支持多数内置类型,能处理Date、Map、Set、ArrayBuffer等,但不支持function和undefined - 手写递归函数 —— 可控性强,能定制对特殊类型的处理逻辑,但需自行规避循环引用(用
WeakMap缓存已遍历对象)
const original = {
a: 1,
b: [2, { c: 3 }],
d: new Date(),
e: /test/g
};
const cloned = structuredClone(original); // ✅ 支持 Date 和正则
console.log(cloned.d instanceof Date); // true
console.log(cloned.e instanceof RegExp); // true
哪些情况必须用深拷贝?
当操作涉及以下任一场景时,浅拷贝不够用:
- 将对象传入第三方库并可能被内部修改(如图表库、表单校验器)
- Vue/React 中需基于原始数据生成新状态,且该状态含嵌套结构
- 做 undo/redo 功能,需保存历史快照
- 测试中需复位对象到初始状态,但原对象在其他地方持续使用
特别注意:structuredClone() 在 Node.js 中需启用 --experimental-structured-cloning 标志(v17~v18),v19+ 默认开启;前端使用前建议检查 typeof structuredClone === 'function'。
容易被忽略的坑
深拷贝不是银弹。即使用了 structuredClone,遇到 function、undefined、Promise、Error 或自定义类实例时仍会失败或丢失行为。如果对象里有 this 绑定的方法、闭包变量或私有字段(#field),任何序列化方案都无法还原其运行时语义。
真正安全的“完全复制”,往往需要结合业务逻辑手动构造,而不是依赖通用拷贝函数。











