JSON 恰好有六种值类型:字符串、数字、布尔值、null、数组和 对象。规范中没有任何内容会添加第七种。这个简短的列表说出来很容易, 但在实践中却出奇地容易出错,主要出在每种类型的边界情况上, 这些边界情况是语言自身的原生类型所没有的。
字符串
用双引号括起来的文本,永远不要用单引号。'hello' 不是合法的 JSON,
只有 "hello" 才是。字符串内有少数几个字符需要转义:
引号本身(\")、反斜杠(\\),以及控制字符
\n、\r、\t、\b 和 \f。其他所有内容,包括大多数 Unicode 文本,
只要文件本身是有效的 UTF-8,就可以不转义地直接写入。JSON Escape
and Unescape 可以双向转换,
并精确报告是哪个字符导致了格式错误的转义序列,
而不是给出一个泛泛的解析错误。
数字
只有一种数字类型,不像某些语言那样有独立的整数和浮点类型。
JSON 数字是一串数字、一个可选的小数点和一个可选的指数:42、-3.14、2.5e10。
没有十六进制,没有 Infinity,没有 NaN,非零数字前不能有前导零(0123 是
无效的,0.123 可以)。这里最尖锐的边界情况是:JavaScript 自身的 Number
类型是 64 位浮点数,无法精确表示超过约 2^53(约九千万亿)
的所有整数。在浏览器控制台中用 JSON.parse 解析包含 64 位
数据库 ID 或 Snowflake ID 的 JSON 文档时,末尾的数字可能会被默默四舍五入。
本站的 JSON Formatter 基于令牌流而非
JSON.parse,专门确保二十位整数往返时不会被四舍五入,
并且会报告那些无法安全表示的数字,而不是默默四舍五入。
布尔值
恰好两个字面量值,小写,不加引号:true 和 false。
"true" 是字符串,不是布尔值,当一个应该是布尔值的字段在上游某处被序列化为文本时,
这是 bug 的常见来源。
null
一个字面量值,小写,不加引号:null。它表示对值的刻意缺失,
这与完全缺失的键是不同的事情。{"middleName": null} 表示“这个人没有中间名,
而且我们检查过了。“一个完全没有 middleName 键的文档对是否存在中间名
什么也不说。将两者混为一谈(将缺失键和 null 值互换使用)的 API
会让接收端无法恢复这种区别。
数组
一个有序列表,[ ],逗号分隔,可以包含任何类型的元素,包括
同一数组中的混合类型:[1, "two", true, null] 是合法的 JSON,虽然
作为 schema 选择会很奇怪。顺序是有保证的且具有意义;
相同元素但顺序不同的两个数组是不同的值。
对象
一个键值对的无序集合,{ },键始终是字符串(即使是
看起来像数字的键如 "2" 也是字符串而非数字),值可以是任何类型。
一个对象中两个同名的键并不违反语法规则,
虽然规范将这种行为描述为“不推荐”并将后续处理交给解析器;
大多数实现(包括 JSON.parse)会默默保留最后一个并丢弃之前的。
JSON Validator 会将重复键标记为
警告,而不是默默放行包含重复键的文档,因为哪个值会保留下来
是应该做出明确决定的那种事情。
六种类型都不能包含什么
没有日期类型:时间戳是字符串,几乎总是 ISO 8601 格式
("2026-08-24T10:00:00Z"),这是惯例而非 JSON 自身强制的。
没有 undefined:在 JavaScript 中会是 undefined 的键在对象中
被省略,而不是用该值写出,因为 JSON 根本没有对应的字面量。
没有函数,没有 Map 或 Set,文档中没有任何地方可以放注释。
需要这些功能的格式(例如带内联注释的配置文件)
是在有意选择一种不同的格式,而不是 JSON 的扩展;
参见 JSON vs YAML 了解注释支持和其他一些便利性
所带来的权衡。
试试看
将任何文档粘贴到 JSON Viewer 中,每个 值都会在树中获得自己的颜色和徽章,这是一种快速查看文档类型标注的方式, 无需逐字符阅读原始文本。要一览语法规则,请查看 JSON Cheat Sheet。