JSON.stringify+parse不能直接用,仅适用于简单对象,会丢失undefined/function/Symbol/BigInt且无法处理循环引用;structuredClone更优但不支持function/undefined/Symbol且兼容性有限;手写需注意类型判断、WeakMap缓存及内置对象特殊处理;lodash.cloneDeep覆盖广但体积大、不还原行为。

JSON.stringify + JSON.parse 能不能直接用?
能快速实现简单对象的深拷贝,但有严重限制:undefined、function、Symbol、BigInt、循环引用都会丢失或报错。比如:
const obj = { a: 1, b: () => {}, c: undefined, d: Symbol('x') };
JSON.parse(JSON.stringify(obj)); // { a: 1 }
遇到 TypeError: Converting circular structure to JSON 就说明存在循环引用——这是最常被忽略的崩溃点。
structuredClone 是不是万能解?
它是目前最接近“标准深拷贝”的原生方案,支持 Map、Set、Date、RegExp、ArrayBuffer 等,且能处理循环引用。
- 但仅在较新环境支持(Chrome 98+、Firefox 94+、Node.js 17.0+)
- 不支持
function、undefined、Symbol—— 这些值会被静默丢弃 - 无法拷贝带有不可枚举属性或原型方法的对象
const obj = { a: new Map([[1, 'one']]), b: { nested: true } };
obj.b.ref = obj; // 循环引用
structuredClone(obj); // ✅ 成功
手写递归深拷贝要注意什么?
核心是类型判断 + 递归 + 缓存循环引用。常见疏漏点:
立即学习“Java免费学习笔记(深入)”;
- 没处理
null(typeof null === 'object',会误入对象分支) - 用
Array.isArray()判断数组,别用instanceof Array(跨 iframe 失效) - 没用
WeakMap缓存已遍历对象,导致循环引用栈溢出 - 对
Date、RegExp等内置对象没做特殊构造(直接new Date(obj)或new RegExp(obj))
示例关键逻辑片段:
function deepClone(obj, cache = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (cache.has(obj)) return cache.get(obj);
const cloned = Array.isArray(obj) ? [] : {};
cache.set(obj, cloned);
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
cloned[key] = deepClone(obj[key], cache);
}
}
return cloned;
}
为什么 lodash.cloneDeep 不是银弹?
它覆盖了绝大多数边缘场景(Map/Set/循环引用/类数组等),但仍有代价:
- 体积大(即使只用 cloneDeep,tree-shaking 也不总可靠)
- 对自定义类实例默认只拷贝可枚举属性,不调用构造函数或
toJSON - 某些特殊对象(如
Promise、Generator)会被浅拷贝或降级为普通对象 - 若传入含
getter的对象,结果可能和预期不符(getter 不执行,只取当前返回值)
真正容易被忽略的是:深拷贝永远无法还原“行为”。哪怕拷贝成功,obj.method === cloned.method 依然为 false,闭包状态、内部私有字段、绑定的 this 都已丢失。











