JSON深拷贝会使Date变字符串而丢失类型和方法,RegExp变{},Function/undefined/Symbol消失,NaN/Infinity变null,Map/Set/BigInt等无法序列化;可用replacer+reviver修复Date,或用Lodash cloneDeep、手写递归处理。

直接用 JSON.parse(JSON.stringify(obj)) 做深拷贝时,Date 对象会被转成 ISO 格式字符串,丢失其对象类型和方法(比如 .getTime()、.getFullYear()),后续调用会报错。这不是 bug,而是 JSON 规范本身不支持 Date 类型——它只认字符串、数字、布尔、null、数组和普通对象。
识别哪些值在 JSON 拷贝中会“变形”
除了 Date,以下类型同样无法保留原貌:
-
RegExp→ 变成空对象{} -
Function、undefined、Symbol→ 完全消失 -
NaN、Infinity→ 变成null -
Map、Set、BigInt、TypedArray→ 无法序列化,多数变为空或报错
用原生方式修复 Date 的深拷贝
可以在 JSON.stringify 的第二个参数(replacer)中拦截 Date,把它转为带类型标记的结构;再在 JSON.parse 的第二个参数(reviver)中还原:
function cloneWithDate(obj) {
const dateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/;
const str = JSON.stringify(obj, (key, value) => {
if (value instanceof Date) {
return { __type: 'Date', value: value.toISOString() };
}
return value;
});
return JSON.parse(str, (key, value) => {
if (value && typeof value === 'object' && value.__type === 'Date') {
return new Date(value.value);
}
return value;
});
}
这样 new Date('2025-03-15') 拷贝后仍是 Date 实例,instanceof Date 返回 true。
更稳妥的替代方案
如果项目允许引入轻量依赖,推荐使用 Lodash 的 cloneDeep,它已内置对 Date、RegExp、Map、Set、循环引用等的完整支持:
import cloneDeep from 'lodash/cloneDeep'; const copied = cloneDeep(originalObj); // Date 保持不变
若必须零依赖,可手写递归深拷贝函数,对 value instanceof Date 分支单独处理:new Date(value.getTime()) 或 new Date(value.toString())。
开发时快速自查的小技巧
拷贝完成后,别只看打印结果——加一行类型校验:
console.assert(copied.createTime instanceof Date, 'createTime 应为 Date 类型');
或者在关键逻辑前做防御性判断:
if (!(copied.date instanceof Date)) {
copied.date = new Date(copied.date); // 尝试从字符串恢复
}
不复杂但容易忽略











