深拷贝是创建完全独立的新对象,与原对象内存隔离;Object.assign()等为浅拷贝;JSON.parse(JSON.stringify())最快但限制多;递归实现需WeakMap防循环引用;Lodash的cloneDeep()最稳妥。

深拷贝就是复制出一个完全独立的新对象
JavaScript 中的 Object.assign()、展开运算符 {...obj} 或直接赋值 let b = a 都只是浅拷贝——它们只复制第一层属性,嵌套的对象或数组仍然共享引用。一旦修改嵌套内容,原对象也会被意外改变。深拷贝的目标是让新对象和原对象在内存中彻底隔离,互不影响。
JSON.parse(JSON.stringify()) 最快但限制多
这是最常用的“取巧”方式,适合纯数据对象(只含字符串、数字、布尔、null、数组、普通对象),不支持 Date、RegExp、undefined、function、Symbol、BigInt 或循环引用。遇到这些会静默丢失或报错。
const obj = { a: 1, b: { c: 2 } };
const copy = JSON.parse(JSON.stringify(obj));
copy.b.c = 99;
console.log(obj.b.c); // 2 —— 原对象未变
-
undefined和函数会被忽略 -
Date变成字符串(如"2023-01-01T00:00:00.000Z") - 循环引用直接抛
TypeError: Converting circular structure to JSON
递归实现能处理函数和 Date,但要小心循环引用
手写深拷贝的核心是:遍历每个属性,对对象/数组递归调用自身,对基本类型直接返回。关键难点在于检测并缓存已访问过的对象,避免无限递归。
function deepClone(obj, map = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (map.has(obj)) return map.get(obj);
const cloned = Array.isArray(obj) ? [] : {};
map.set(obj, cloned);
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
cloned[key] = deepClone(obj[key], map);
}
}
return cloned;
}
- 用
WeakMap缓存源对象 → 克隆对象映射,解决循环引用 - 保留
Date、RegExp、Map、Set等类型需额外判断分支 - 无法克隆
function的作用域或闭包,但函数本身可被复制(因函数是对象,且通常不需要“深”进函数体)
Lodash 的 cloneDeep() 是生产环境最稳妥的选择
它覆盖了几乎所有边界情况:Map、Set、TypedArray、Buffer、Error、循环引用、不可枚举属性、原型链等。体积稍大,但省去自己踩坑的成本。
立即学习“Java免费学习笔记(深入)”;
import { cloneDeep } from 'lodash-es';
const obj = { date: new Date(), map: new Map([['a', 1]]) };
const copy = cloneDeep(obj);
console.log(copy.date instanceof Date); // true
console.log(copy.map.size); // 1
- 不依赖全局
JSON,兼容性更好 - 对
undefined、Symbol、BigInt也能保留(取决于版本) - 如果项目已用 Lodash,直接用;否则引入单个函数比手写更可靠











