json深拷贝不是真正深拷贝,而是数据快照还原;会静默丢失function/undefined/symbol,date/regexp/map/set等失真,循环引用直接崩溃,原型链断裂且nan/infinity变null。

JSON 序列化深拷贝(即 JSON.parse(JSON.stringify(obj)))不是真正意义上的深拷贝,而是一种“数据快照还原”。它在多数简单场景下看似有效,但一旦涉及真实业务对象,就会暴露多个**不可忽视的致命缺陷**。避坑的关键不是修补它,而是换掉它。
会静默丢失关键类型:Function、undefined、Symbol
JSON 标准只支持字符串、数字、布尔、null、数组和普通对象。其余类型在序列化时被强制过滤或转换:
- 函数直接被跳过——对象中方法消失,调用时报
TypeError: xxx is not a function -
undefined字段被完全忽略,导致属性缺失,可能引发后续逻辑空指针 - Symbol 键及对应值全部丢弃,
Reflect.ownKeys()和Object.getOwnPropertySymbols()结果为空
特殊对象全部失真:Date、RegExp、Map、Set 全军覆没
这些类型无法映射为 JSON 原生结构,结果是语义和行为双重破坏:
- Date 变成 ISO 字符串,
instanceof Date为 false,.getTime()等方法不可用 - RegExp 变成空对象
{},.test()、.exec()全部失效,flags 和 source 信息丢失 - Map/Set 被转成空对象或
undefined,键值对结构彻底瓦解 - Error、BigInt、TypedArray、ArrayBuffer 等直接报错或产出无效数据
循环引用直接崩溃:TypeError 无法捕获或降级
只要对象内部存在自引用或闭环引用(如 a.b = a),JSON.stringify() 就会抛出不可恢复的错误:
- 错误信息模糊:
Converting circular structure to JSON,不提示具体路径 - 无法通过 try/catch 后续补救——序列化阶段已中断,无中间态可取
- 前端监控难以定位,常表现为白屏或接口静默失败
其他隐蔽风险:原型链断裂、NaN/Infinity 变 null、稀疏数组错乱
这些细节问题往往在上线后才暴露,排查成本高:
- 所有原型方法、getter/setter、constructor 信息清零,自定义类实例退化为裸对象
-
NaN、Infinity、-Infinity统一变成null,数值逻辑异常 - 稀疏数组(如
[1, , 3])被转为[1, null, 3],长度和遍历行为改变 - 非字符串 key(如数字
0、布尔true)被自动转为字符串,影响 Map-like 使用
真正可靠的替代方案
根据运行环境与需求选择:
-
现代环境(Chrome 98+ / Firefox 94+ / Node.js 18.13+):优先用
structuredClone(),一行解决循环引用、Date、RegExp、undefined,且自动防重复引用 -
需兼容旧版或定制行为:手写递归克隆,配合
WeakMap记录已处理对象,对Date、RegExp、Map、Set分支构造,函数可选保留引用或绑定新上下文 -
项目已引入 Lodash:用
_.cloneDeep(),开箱即用,支持绝大多数内置类型;若需保留函数,加customizer回调显式返回 - 仅临时处理纯数据(如配置项、表单初始值):可继续用 JSON 方案,但必须前置校验——确认不含函数、Date、循环引用等











