NaN 和 Infinity 能放進 JSON 嗎
結論:JSON 只有十進位數字字面量,沒有 NaN、Infinity、-Infinity。JSON.stringify 會靜默把它們變成 null,介面因此出現過大量「明明是數字卻收到 null」的故障。

結論:不能。JSON 只允許十進位數字字面量,JSON.stringify 會把 NaN 和 Infinity 靜默序列化成 null;要表達這類狀態,用 null 加一個說明原因的狀態欄位,或使用帶明確約定的字串。
JSON.stringify({ ratio: NaN, limit: Infinity });
// '{"ratio":null,"limit":null}'
沒有任何報錯,也沒有任何警告,兩個值直接變成 null。
標準裡為什麼沒有
RFC 8259 的數字語法是:
number = [ minus ] int [ frac ] [ exp ]
只認十進位字面量。NaN、Infinity 是 IEEE 754 的特殊值,不是數字字面量;寫進 JSON 文字,解析器會當成非法識別字。JSON 的目標是跨語言可解析,而這些特殊值在不同語言裡的表示與比較語意都不一致,乾脆排除。
各語言的實際行為
| 語言 | 行為 |
|---|---|
JavaScript JSON.stringify |
靜默轉成 null |
Python json.dumps |
預設輸出 NaN(非標準),allow_nan=False 時拋 ValueError |
Go encoding/json |
序列化時報錯 unsupported value: NaN |
| Java Jackson | 預設輸出 "NaN" 字串,可配置為拋錯 |
同一個值,四種行為。跨語言介面出現「數字欄位偶爾是 null」時,先懷疑這一層。
該用什麼表達
一、字串約定。 用 "NaN"、"Infinity" 加型別說明。缺點是把判斷推給每個呼叫方。
二、null + 狀態欄位。 更推薦:值不可用時給 null,另加一個欄位說明原因,例如 {"avgLatency": null, "avgLatencyStatus": "no-sample"}。
三、換個單位。 很多「除以零得到 Infinity」的場景,本質是沒有樣本。直接回 null 並讓前端顯示「暫無資料」,比傳無窮大更接近業務事實。
順手檢查
- 前端把
JSON.parse結果直接餵給圖表庫,null會讓折線斷開——確認這是預期行為 JSON.stringify還會丟掉undefined、函式、Symbol,這些鍵會整個消失- 後端用 Python 的
json.dumps且allow_nan為預設True,產出的就不是標準 JSON
常見問題
遇到「數字欄位收到 null」應該怎麼排查?
先確認該欄位在序列化前是不是 NaN 或 Infinity。JavaScript 的 JSON.stringify 會把這兩種特殊浮點靜默轉成 null,Go 會直接報錯,Python 預設則輸出非標準的 NaN。
是否可以用字串 "NaN" 表示特殊值?
可以,但要配上明確的型別約定,讓每個消費方顯式判斷。更穩妥的做法是值不可用時給 null,另加一個狀態欄位說明原因。