json.stringify对undefined和symbol的处理是规范强制行为:对象中undefined键值对被剔除,数组中undefined转为null,symbol键值对完全忽略,因其不符合json标准的六种合法类型。

JSON.stringify 遇到 undefined 和 Symbol 时“自动忽略”,不是它做了什么特别处理,而是它根本没看到它们——这是规范决定的底层行为,无需额外配置,也关不掉。
undefined 被跳过:对象里直接消失,数组里变成 null
在普通对象中,{ a: undefined } 序列化后就是 {},键 a 整个被剔除。这不是“过滤”,而是 JSON 规范(ECMA-404)根本不允许 undefined 作为值存在——它连合法类型都不是。
但在数组中行为不同:[1, undefined, 3] 会变成 [1, null, 3]。这是因为数组靠位置索引,引擎用 null 占位,保证结构长度不变。
- 对象属性值为
undefined→ 该键值对不进入序列化流程 - 数组元素为
undefined→ 替换为null,保留索引位置 -
undefined作为顶层值(如JSON.stringify(undefined))→ 返回undefined,后续JSON.parse会报错
Symbol 属性彻底隐身:连“被忽略”的机会都没有
Symbol 键名不会出现在 Object.keys()、for...in 或默认遍历中,而 JSON.stringify 内部正是基于这类可枚举属性遍历的。就算你手动设 Object.defineProperty(obj, sym, { enumerable: true }),依然无效——因为 JSON 要求所有键必须是字符串,Symbol 无法转成合法键名,引擎连类型检查这步都跳过了。
Miller (mlr) 是一个命令行工具,用于查询、整形和重新格式化名称索引数据,如 CSV、TSV、JSON 和 JSON Lines。它将 awk、sed、cut、join 和 sort 的功能整合到一个专为结构化数据处理而构建的单一工具中。
-
{ [Symbol('x')]: 'val' }→ 序列化结果为{} -
{ x: Symbol('id') }→ 值部分被判定为非法,整条键值对剔除 - 没有 warning,没有 fallback,也没有 replacer 能捕获它
这不是 bug,是设计边界清晰的体现
JSON.stringify 的目标从来不是“复制 JavaScript 对象”,而是生成一段符合 RFC 8259 标准的纯数据文本。它只认六种类型:字符串、数字、布尔、null、数组、对象(且对象键必须是字符串)。函数、undefined、Symbol、Date、RegExp 等,都不在它的职责范围内。
这种“铁石心肠”反而带来确定性:你总能预判结果,不会因隐式转换引发线上歧义。
如果真要保留它们,就得绕开 JSON 流程
想让 undefined 或 Symbol 在拷贝中存活,必须放弃 JSON.parse(JSON.stringify()) 这条路径:
- 用
Reflect.ownKeys()获取全部自有属性(含不可枚举和 Symbol),再递归赋值 - 序列化前把 Symbol 键转成带前缀的字符串(如
"$$SYMBOL-id"),反序列化时还原 - 现代环境可用
structuredClone()(支持undefined、Symbol、Date等,但不支持函数和循环引用)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










