JSON深拷贝失效是因为stringify会忽略函数、undefined、Symbol等非可序列化值,replacer仅能转换而无法还原类型,需配合reviver才能实现伪深拷贝;更优解是用structuredClone或lodash.cloneDeep。

JSON 方法深拷贝失效,是因为 JSON.stringify 会忽略函数、undefined、Symbol、BigInt、循环引用、Date 对象、RegExp 对象、Map/Set 等非可序列化值。即使你用 replacer,它也只在序列化阶段起作用,且无法恢复原始类型(比如 Date 还是变成字符串)。所以不能靠 replacer 实现真正可靠的深拷贝,但可以用它“尽量保留信息”或“避免报错”,再配合后续解析逻辑还原关键结构。
replacer 能做什么:过滤/转换,而非还原类型
replacer 是一个函数或数组,用于在 stringify 过程中修改键值对。它不能让 JSON 支持新类型,只能把不可序列化的值替换成可序列化的等价形式。例如:
- Date → 转成 ISO 字符串(
date.toISOString()) - RegExp → 转成对象
{ $regex: pattern, $flags: flags } - undefined / function → 返回
null或跳过(返回 undefined 即删除该字段) - 循环引用 → 在发现前记录已访问对象,遇到重复时返回占位符(如
"[Circular]")
带类型标记的 replacer 示例(便于后续解析)
下面是一个兼顾安全与可还原性的 replacer 写法,为特殊值添加类型标识:
function smartReplacer(key, value) {
if (value instanceof Date) {
return { $type: 'Date', value: value.toISOString() };
}
if (value instanceof RegExp) {
return { $type: 'RegExp', value: value.source, flags: value.flags };
}
if (value instanceof Map) {
return { $type: 'Map', value: Array.from(value) };
}
if (value instanceof Set) {
return { $type: 'Set', value: Array.from(value) };
}
if (typeof value === 'function' || value === undefined) {
return null; // 或返回 { $type: 'Function', value: '[Function]' }
}
return value;
}
这样序列化后,虽然还是 JSON 字符串,但关键结构没丢,后续可用自定义解析器还原。
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
配套 parse 处理才能完成“伪深拷贝”
仅靠 replacer 不够,必须搭配 JSON.parse 的 reviver 函数来重建对象:
-
reviver接收每个键值对,在解析过程中判断$type字段 - 遇到
{ $type: 'Date', value: '2024-...' }→ new Date(value) - 遇到
{ $type: 'Map', value: [['a',1]] }→ new Map(value) - 注意:reviver 无法还原函数体,只能留空或标记
更稳妥的选择:不用 JSON,改用 structuredClone 或库
现代浏览器支持 structuredClone(),能正确处理 Map、Set、Date、RegExp、ArrayBuffer 等,且不丢失类型:
const copied = structuredClone(original); // 原生、可靠、简单
若需兼容旧环境,推荐使用 lodash.cloneDeep 或 fast-deep-cloning 等成熟库——它们内部不依赖 JSON,而是递归遍历+类型判断+构造新实例。

















