深拷贝需处理类型丢失、循环引用、特殊对象及属性描述符等问题,JSON方法无法正确处理undefined、函数、Symbol、BigInt及循环引用,且会忽略原型链和不可枚举属性,推荐使用Lodash的cloneDeep以确保可靠性。

JavaScript中的深拷贝看似简单,实则隐藏多个边界情况和陷阱。直接使用JSON.parse(JSON.stringify())虽然常见,但容易出问题。以下是实际开发中需要特别注意的几个关键点。
1. 无法处理的数据类型
某些JS原生类型在序列化过程中会丢失或被转换:
- undefined:会被直接忽略,对象属性消失
-
函数(Function):JSON不支持,拷贝后变为
null或丢失 - Symbol:完全被忽略,属性不存在于结果中
-
BigInt:
JSON.stringify()会抛错
{ a: undefined, b: () => {}, c: Symbol('test') } 经过 JSON 方法拷贝后只剩空对象。
2. 循环引用导致栈溢出
当对象存在循环引用时,JSON.stringify() 会抛出错误:
const obj = {}; obj.self = obj; JSON.stringify(obj); → 报错 "Converting circular structure to JSON"
自实现递归深拷贝若无检测机制,也会引发栈溢出。解决办法是维护一个WeakMap记录已访问对象,发现重复引用时直接返回原引用。
立即学习“Java免费学习笔记(深入)”;
3. 特殊对象与内置类型处理不当
以下对象不会按预期拷贝:
-
Date 对象:JSON方法能保留,但手动递归需特别判断
instanceof Date - RegExp 对象:正则表达式会被转成空对象或字符串
- Set / Map:内容丢失,需单独处理构造逻辑
- ArrayBuffer / TypedArray:二进制数据可能无法正确复制
这些类型需要逐一识别并调用对应的构造方式还原。
4. 原型链与属性描述符丢失
深拷贝通常只复制可枚举的自身属性,以下内容不会被保留:
- 对象的原型(
__proto__) - 不可枚举属性(如
Object.keys()拿不到的) - 属性的 getter/setter、writable/enumerable 等 descriptor 信息
基本上就这些。真正可靠的深拷贝需要递归判断类型、处理循环引用、还原特殊对象,并根据业务决定是否保留描述符。多数场景下推荐使用成熟库如 Lodash 的 cloneDeep,避免重复踩坑。










