语法与六种值:规范级细节
基于 RFC 8259 / ECMA-404 · JSON Schema 2020-12 · 核于 2026-07
速查
- 六个结构字符:
[]{}:,;空白(空格/制表/换行/回车)可出现在任意两个 token 之间。 - 对象:
{},键必双引号字符串,SHOULD唯一;重复键行为未定义,多数实现保留最后一个。 - 数组:
[],有序、元素类型可异构,无尾逗号。 - 字符串转义(仅这 8+1 种):
\"\\\/\b\f\n\r\t与\uXXXX(四位十六进制)。控制字符 U+0000–U+001F 必须转义。 \uXXXX只编码一个 16 位码元;BMP 之外的字符(码点 > U+FFFF)用代理对(两个\u,如 😀 =😀),也可直接用 UTF-8 原样写。- 数值规则:十进制;无前导零(
007❌)、整数部分不可省(.5❌)、无十六进制/八进制(0xFF❌)、无NaN/Infinity;可负号、可小数、可指数e/E(6.022e23)。 - 数字精度:互操作性只保证 IEEE 754 双精度范围;安全整数区间 [-(2^53−1), 2^53−1],超出即不可靠。
true/false/null:全小写字面量,大小写敏感。- 编码:跨系统交换 MUST 用 UTF-8;MUST NOT 添加 BOM(U+FEFF),解析方 MAY 忽略已存在的 BOM。
- 顶层:任意合法值(RFC 8259 放宽,不再限对象/数组)。
- 无注释、无尾逗号——要这些能力去看 变体页。
一、结构字符与空白
JSON 只有 6 个结构字符:[ ](数组括号)、{ }(对象括号)、:(键值分隔)、,(元素/键值对分隔)。
空白(space U+0020、tab U+0009、换行 U+000A、回车 U+000D)可以插入在任意两个 token 之间——所以 JSON 可以紧凑成一行,也可以缩进美化,语义完全一致:
{"a":1,"b":[2,3]}等价于
{
"a": 1,
"b": [2, 3]
}只有这四种是空白
JSON 的「空白」严格限定为上述四个字符。其它 Unicode 空白(如不换行空格 U+00A0)不算 JSON 空白,出现在 token 之间会导致解析失败。
二、对象:键必双引号,重复键要警惕
对象是无序的键值对集合:
{ "name": "Ada", "age": 36, "tags": ["math", "cs"] }- 键必须是双引号字符串(这是与 JS 字面量的核心差异)。
- RFC 8259 规定对象内的名字
SHOULD(应当)唯一,但没有强制禁止重复。 - 出现重复键时行为「未定义/不可预测」——实践中多数实现保留最后一个:
JSON.parse('{"a":1,"a":2}'); // { a: 2 } ← 保留最后一个生产中应避免依赖重复键:不同解析器行为可能不同,还可能被利用制造解析歧义(一种安全隐患,如前后端对同一字段解读不一致)。
三、字符串与转义
字符串是双引号包裹的零或多个 Unicode 字符,用反斜杠转义。合法转义只有这些:
| 转义 | 含义 |
|---|---|
\" | 双引号 |
\\ | 反斜杠 |
\/ | 斜杠(可选转义,</script> 场景常用) |
\b \f \n \r \t | 退格 / 换页 / 换行 / 回车 / 制表 |
\uXXXX | 四位十六进制指定的 Unicode 码元 |
控制字符必须转义
U+0000 到 U+001F 的控制字符(含真实换行、制表符)不能裸出现在字符串里,必须转义。所以 JSON 字符串里没有「多行字符串」——想换行只能写 \n。
\u 与代理对(astral 字符)
\uXXXX 只能编码一个 16 位码元。对基本多文种平面(BMP)之外的字符(码点 > U+FFFF,如大部分 emoji),要用 UTF-16 代理对——两个 \u 转义拼成 12 字符序列:
{ "emoji": "😀" } // 😀 U+1F600因为 JSON 交换用 UTF-8,你也完全可以直接把字符原样写进去:{ "emoji": "😀" } 同样合法,且更易读。\u 转义主要用于确保纯 ASCII 传输通道下也不丢字符。
四、数值:最容易踩的严格规则
JSON 数字「很像 C/Java 的数字,但不用八进制和十六进制」。语法要点:
-? 整数部分 (.小数部分)? (e/E [+/-] 指数)?允许:0、-1、3.14、-0.5、6.022e23、1E-10
非法(常见坑):
| 写法 | 为什么非法 |
|---|---|
007 | 前导零不允许(0 后不能直接跟数字) |
.5 | 整数部分不可省略,须写 0.5 |
5. | 小数点后须有数字,须写 5.0 |
0xFF | 无十六进制 |
+1 | 不允许显式正号 |
NaN / Infinity | 无法用数字语法表示,明确禁止 |
精度:双精度浮点与安全整数
RFC 8259 明确:良好互操作性建立在实现「不期望超过 IEEE 754 双精度(binary64) 的精度与范围」之上。这意味着:
- 安全整数区间是 [-(2^53−1), 2^53−1](即 ±9007199254740991)。
- 超出此范围的整数跨实现不可靠——JS 里会静默丢精度:
JSON.parse('{"id": 9999999999999999}').id; // 10000000000000000 ← 已失真大整数(订单号、雪花 ID、区块链数值)应用字符串承载传输,前端按字符串或 BigInt 处理。详见 JS API 页。
五、字面量:全小写
只有三个字面量名,且大小写敏感、必须全小写:true、false、null。True、FALSE、Null、nil、None 全部非法。
六、编码与 BOM
- 编码:RFC 8259 规定,在非封闭生态间交换的 JSON 文本 MUST 使用 UTF-8。(旧 RFC 4627 曾允许 UTF-16/32,已收敛。)这也是
application/json媒体类型不带 charset 参数的原因。 - BOM:实现 MUST NOT 在网络传输的 JSON 开头添加字节序标记(U+FEFF);接收方 MAY 忽略已存在的 BOM(不强制报错)。
BOM 是隐蔽坑
Windows 记事本另存的 UTF-8 常带 BOM,某些严格解析器会因此报错,或让第一个键名前多出不可见字符。跨系统传 JSON、读磁盘上的 .json 配置时,留意去掉 BOM。
七、无注释、无尾逗号
标准 JSON 不支持任何注释(//、/* */ 都非法),也不允许尾逗号。这是它作为「机器交换格式」的刻意克制。要注释/尾逗号,请用 JSON5 或 JSONC。
语法规则掌握后,进入 JS 中的 JSON API:JSON.parse 的 reviver、JSON.stringify 的 replacer/space/toJSON,以及 undefined/循环引用/Date/大整数/BigInt 一整套坑。