json深拷贝并非真正覆盖属性,而是序列化时按规则静默丢弃或转换值:函数、undefined(对象中)、symbol键、regexp、map/set等被忽略;date转字符串;循环引用抛错;仅保留自有可枚举属性。

JSON 方法本身不涉及“属性覆盖”逻辑,它只是序列化再反序列化的过程。所谓“覆盖”,其实是 JSON.stringify() 在序列化阶段对某些值的静默丢弃或强制转换,导致最终拷贝结果中某些属性“看起来像被覆盖了”,实则是根本没被保留。
JSON 深拷贝中属性丢失或变形的规则
JSON.stringify(obj) 会按固定规则处理不同类型的值,这些规则直接决定了哪些属性能进入最终拷贝、哪些会被跳过或改写:
-
函数(function):整个键值对被完全忽略
const obj = { name: "Alice", sayHi: () => "hi" }; JSON.stringify(obj); // → '{"name":"Alice"}' —— sayHi 消失 -
undefined:作为属性值时被忽略;作为对象属性的值或数组元素时,该位置变成
null(数组中)或整个键被删(对象中)const obj = { a: 1, b: undefined, c: null }; JSON.stringify(obj); // → '{"a":1,"c":null}' -
Symbol 键:无论键还是值,全部被忽略
const sym = Symbol('key'); const obj = { [sym]: 'won\'t appear', d: 'ok' }; JSON.stringify(obj); // → '{"d":"ok"}' -
Date 对象:转为 ISO 字符串格式
const obj = { time: new Date(2026, 5, 24) }; JSON.stringify(obj); // → '{"time":"2026-06-24T00:00:00.000Z"}' -
RegExp 对象:变成空对象
{}
Comprehensive Three.js 3D graphics reference下载详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
const obj = { re: /abc/g }; JSON.stringify(obj); // → '{"re":{}}' -
Map / Set / ArrayBuffer / TypedArray / Blob / Error 等:无法序列化,对应属性被丢弃(或抛错)
const obj = { map: new Map([['a', 1]]) }; JSON.stringify(obj); // → '{}' -
循环引用:直接抛出
TypeError,整个过程失败,无拷贝结果const obj = { a: 1 }; obj.self = obj; JSON.stringify(obj); // → TypeError: Converting circular structure to JSON 不可枚举属性、原型链属性、getter/setter:全部不参与序列化,只处理自有可枚举属性
实际效果等价于“覆盖”的典型情况
- 原对象有
undefined属性,拷贝后该属性不存在 → 像被“覆盖掉” - 原对象有
Date,拷贝后变成字符串 → 类型变了,但键名还在,值已非原意 - 多个同名属性(如对象字面量中重复键),
JSON.stringify用最后一个为准(这是 JS 解析规则,非 JSON 特有)
替代建议:需要保真就别用 JSON
如果业务依赖函数、日期对象行为、正则匹配能力、或 Map/Set 结构,JSON.parse(JSON.stringify()) 不是深拷贝,而是“数据清洗式降级”。
更稳妥的选择包括:
- 现代环境用
structuredClone()(支持 Date、RegExp、Map、Set、循环引用) - 生产项目引入
lodash.cloneDeep - 自定义递归 +
WeakMap处理循环引用 + 类型判断
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










