前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库JSON.stringify 转换 undefined function Symbol
JavaScript值与类型

JSON.stringify 遇到 undefined、函数和 Symbol 会怎么处理?

JSON 里没有 undefined、函数和 Symbol 这三种值,所以 JSON.stringify 只能想办法绕开:在对象里整个属性被丢掉,在数组里换成 null,直接序列化它们本身则返回 undefined。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#值与类型
先看核心答案读代码示例
理解线索

同一个值,放的位置不同结果不同

  1. 对象属性值是 undefined、函数、Symbol 时整个键值对被跳过
  2. 数组元素换成 null,否则后面元素的下标会错位
  3. 顶层值JSON.stringify(undefined) 返回的是 undefined,不是 "undefined"

Symbol 作为属性名时也会被忽略,不管值是什么。这和值是 Symbol 是两回事,但结果都是这个属性不出现在 JSON 里。

核心回答

先记住这个答案

JSON 格式本身只有字符串、数字、布尔、null、对象和数组,没有 undefined、函数和 Symbol。JSON.stringify 碰到这三种值,按所在位置分三种处理:作为对象属性的值时,整个属性被跳过;作为数组元素时,被换成 null;直接把它们传给 JSON.stringify 时,返回值是 undefined。另外 NaN 和 Infinity 会变成 null,循环引用和 BigInt 会抛 TypeError。

  • 对象属性值是这三种时,属性直接消失
  • 数组里的这三种值会变成 null,保住下标
  • 直接序列化它们,返回 undefined 而不是字符串
  • 循环引用与 BigInt 会报错

先看三种位置的输出

把同一组值分别放进对象、数组,再单独序列化,差别一眼就能看出来。

对象、数组、顶层值对比JavaScript
const obj = {
  a: undefined,
  b() {},
  c: Symbol('x'),
  [Symbol('key')]: 1, // Symbol 作为键,同样被忽略
  d: null,
  e: NaN
}
console.log(JSON.stringify(obj))
console.log(JSON.stringify([undefined, () => {}, Symbol('x'), 1]))
console.log(JSON.stringify(undefined))
console.log(typeof JSON.stringify(() => {}))
查看输出与解释
{"d":null,"e":null}
[null,null,null,1]
undefined
undefined

对象里 a、b、c 和那个 Symbol 键全没了,只剩 d,而 NaN 被改写成了 null。数组不能随便删元素,删了后面的 1 就从下标 3 跑到下标 0,所以只能用 null 占位。最后两行说明顶层值序列化的结果是真正的 undefined,不是字符串,拿它去拼接或者当请求体发出去,都会出问题。

项目里最常踩的两个坑

第一个坑是用 JSON.parse(JSON.stringify(obj)) 做深拷贝。拷贝完函数和值为 undefined 的字段都丢了,Date 变成了 ISO 字符串,Map、Set 变成了空对象 {}。表单数据这种纯数据还能凑合用,带方法或特殊类型的对象就不行了,现在更推荐 structuredClone,它能处理 Date、Map 和循环引用,但遇到函数会直接抛错。

第二个坑在接口提交上。比如编辑用户资料,前端把清空的昵称设成 undefined,axios 序列化请求体时这个字段直接消失,后端收到的请求里压根没有 nickname,于是认为「不修改」。想表达「清空」必须传 null,null 会原样保留在 JSON 里。反过来,有些团队就是利用这一点,把不想提交的字段设成 undefined 来省掉手动删除。

用 replacer 把 undefined 保留下来
JSON.stringify 的第二个参数 replacer 是个函数,每个键值对都会先经过它。写成 (key, value) => value === undefined ? null : value,值为 undefined 的属性就会以 null 的形式保留。函数和 Symbol 也能用同样的办法转成字符串描述。第三个参数是缩进,调试打印时传 2 可读性好很多。

对象自己决定怎么被序列化

序列化一个值之前,JSON.stringify 会先看它有没有 toJSON 方法,有的话用这个方法的返回值代替原值。Date 能变成字符串,就是因为 Date.prototype.toJSON 返回了 ISO 格式的时间。自己的类也可以加一个 toJSON,比如隐藏密码字段,或者把金额对象输出成数字。

这个顺序要记住:先调用 toJSON,再交给 replacer,最后才按上面的规则丢弃或替换。所以如果 toJSON 返回了 undefined,这个属性照样会被跳过。

回答前,多想一步

容易答错的地方

以为 undefined 会变成 null
只有在数组里才变成 null。对象属性是直接消失,这也是很多人深拷贝后发现字段少了的原因。
以为 NaN 会被保留或报错
JSON 没有 NaN 和 Infinity,它们会被悄悄改成 null,不报错。统计接口里算出 0 / 0,前端拿到的就是 null,排查时很容易误以为是后端没返回。
以为所有异常值都会被静默处理
BigInt 不会被丢掉,而是直接抛 TypeError,要么先转成字符串,要么给 BigInt.prototype 加 toJSON。循环引用同样抛 TypeError,错误信息里会提到 circular structure。
试着用自己的话回答

面试官还会怎么问?

怎么序列化带循环引用的对象?

用 replacer 配合 WeakSet 记录已经访问过的对象,再次遇到同一个对象时返回一个占位字符串或者 undefined 跳过它。日志库打印复杂对象时一般就是这么做的。

JSON.parse 能把丢掉的值还原回来吗?

不能,信息在序列化那一步就没了。JSON.parse 也有第二个参数 reviver,可以把 ISO 字符串转回 Date,但前提是字符串还在,被丢掉的函数和 undefined 找不回来。

Map 和 Set 序列化出来是什么?

都是 {},因为它们的数据不在可枚举的自有属性上。要保存内容,先用 Array.from(map) 或 [...set] 转成数组再序列化。

从一道题,走向一组知识

把知识连起来

值与类型

Symbol.toPrimitive 是怎么让对象自己决定转成数字还是字符串的?

JSON.stringify 会先调用对象的 toJSON,和 Symbol.toPrimitive 一样都是对象自定义转换结果的钩子。

值与类型

为什么字符串方法都返回新字符串,数组方法却会直接改原数组?

序列化得到的是一个新字符串,原对象不受影响,可以顺便理解字符串为什么不可变。

参考资料

  • JavaScript:值与类型参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 先看三种位置的输出
  3. 项目里最常踩的两个坑
  4. 对象自己决定怎么被序列化
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑