前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 NaN Infinity 序列化为null
JavaScript数据处理

JSON.stringify 遇到 NaN 和 Infinity 会怎样?为什么不报错?

JSON 的数字语法里没有 NaN 和 Infinity,所以 JSON.stringify 遇到 NaN、Infinity 或 -Infinity 时会写成 null。不管它在顶层、对象里还是数组里都一样,而且不报错。代价是解析回来只剩一个 null,原来是哪个值已经分不清了。

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

JSON 只认有限的十进制数

  1. JavaScript 里NaN 和 Infinity 都是合法的 Number,能正常参与运算
  2. JSON 里数字语法只有有限的十进制数,没有这几个特殊值
  3. 转换结果统一写成 null,三种值和真正的 null 都分不清了

这些值通常不是故意产生的,而是上游算错了,比如除以 0、对空数组求平均。它们变成 null 发给后端,后端可能当成「未填写」处理,问题就这样被藏起来了。

核心回答

先记住这个答案

JSON 的数字只能是有限的十进制数,语法里没有 NaN、Infinity 和 -Infinity。JSON.stringify 遇到这三个值时不会输出非法的文本,也不会抛错,而是统一写成 null,不管它是顶层值、对象属性还是数组元素。这样生成的 JSON 一定合法,但信息丢了:解析回来只剩 null,和原本就是 null 的值也分不清。所以要在序列化之前处理,发送前用 Number.isFinite 校验;如果特殊值有业务含义,就用 replacer 编码、reviver 解码。

  • NaN、Infinity 和 -Infinity 都会变成 null
  • 不报错,所以数据丢了也很难发现
  • 提交前用 Number.isFinite 校验
  • 确实要保留,就用 replacer 和 reviver 成对编码

先看序列化后的真实文本

三种位置都试一下,再做一次往返。

非有限数都会变成 nullJavaScript
console.log(JSON.stringify(NaN))
console.log(JSON.stringify({ high: Infinity, low: -Infinity }))
console.log(JSON.stringify([1, NaN, Infinity]))

const restored = JSON.parse(JSON.stringify({ value: NaN }))
console.log(restored.value, Number.isNaN(restored.value)) // 回不去了
查看输出与解释
null
{"high":null,"low":null}
[1,null,null]
null false

代码全部正常跑完,一个报错都没有,这正是这个问题难发现的原因。对象里的属性没有被删掉,而是保留了键、值变成 null;数组里也保留了位置。这和 undefined 的处理不同,undefined 在对象里会让整个属性消失。 最后一行说明往返之后拿到的是 null,不是 NaN。如果 NaN 表示「计算失败」、Infinity 表示「没有上限」,默认序列化就把这些不同的业务状态压成了同一个值。

为什么选 null,而不是报错或转字符串
JSON 是跨语言的数据格式,很多语言的解析器不接受 NaN 这样的写法,直接输出会生成非法 JSON。转成字符串 "NaN" 又改变了类型,接收方拿到一个字符串,可能直接拿去显示。null 是 JSON 里唯一能表示「这里没有有效值」的东西,所以规范选了它。

发送前拦住,或者显式编码

金额、坐标、统计指标这类字段,出现 NaN 或 Infinity 基本都是 bug。最稳的做法是提交前用 Number.isFinite(value) 校验,不合法就报错,把问题留在发生的地方。

如果特殊值确实有业务含义,比如「无上限」,就要约定一种编码方式,发送端和接收端成对实现。

用 replacer 编码,reviver 恢复JavaScript
const encode = (key, value) =>
  typeof value === 'number' && !Number.isFinite(value) ? { $num: String(value) } : value
const decode = (key, value) =>
  value && typeof value === 'object' && '$num' in value ? Number(value.$num) : value

const data = { a: NaN, b: Infinity, c: -Infinity, d: 1 }
const json = JSON.stringify(data, encode)
console.log(json)

const back = JSON.parse(json, decode)
console.log(back.a, back.b, back.c, back.d)
查看输出与解释
{"a":{"$num":"NaN"},"b":{"$num":"Infinity"},"c":{"$num":"-Infinity"},"d":1}
NaN Infinity -Infinity 1

replacer 在序列化每个值之前调用,所以能在 NaN 被转成 null 之前把它换掉。String(NaN) 是 'NaN',而 Number('NaN') 又能转回 NaN,对 Infinity 也同理。reviver 从里到外处理,看到带 $num 标记的对象就还原成数字。 这种编码只有两端都认识才有意义。如果只是「没有上限」,更好的做法是在接口里设计一个明确的字段,比如 maxLimit: null 配合 unlimited: true,而不是传一个 JavaScript 特有的值。

回答前,多想一步

容易答错的地方

以为 JSON.stringify 会抛错
BigInt 和循环引用会抛 TypeError,但 NaN 和 Infinity 不会,它们静默变成 null。排查数据丢失时要看输出内容,光靠 try/catch 抓不到。
用全局 isFinite 做校验
全局 isFinite 会先把参数转成数字,isFinite('') 和 isFinite(null) 都是 true,因为它们会被转成 0。接口校验要用 Number.isFinite(value),它不做类型转换,只有真正的有限数字才返回 true。
试着用自己的话回答

面试官还会怎么问?

JSON.parse 能把 null 自动恢复成 NaN 吗?

不能。文本里只剩 null,它可能原本就是 null,也可能来自三个特殊值中的任何一个,已经没有区分的依据。只有序列化时额外编码了类型信息,解析时才能恢复。

为什么 BigInt 报错,NaN 却不报错?

NaN 转 null 是 JSON 最早的规范就定下的行为,改了会破坏大量现有代码。BigInt 是后来加入的类型,委员会认为自动转换一定会丢精度,所以选择报错,逼调用方显式决定怎么编码。

从哪里最容易冒出 NaN?

最常见的是解析失败,比如 Number('abc') 和 parseInt('');其次是对空数组求平均时 0 除以 0;还有读取了不存在的字段再做运算,undefined + 1 就是 NaN。表单提交前对数字字段统一做一次 Number.isFinite 检查,能拦住绝大部分。

从一道题,走向一组知识

把知识连起来

数据处理

接口返回的日期是字符串,怎么用 JSON.parse 的 reviver 转回 Date?

想把编码后的特殊值恢复回来,要在 JSON.parse 的 reviver 里做,和恢复 Date 是同一套写法。

数据处理

JSON.stringify 的第二个参数有什么用?怎么用它过滤和转换属性?

把 NaN 编码成带标记的对象要用 replacer,那题讲清了 replacer 的调用顺序和返回值规则。

参考资料

  • JavaScript:数据处理参考资料

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

本题目录
  1. 先记住这个答案
  2. 先看序列化后的真实文本
  3. 发送前拦住,或者显式编码
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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