JSON 入门:语法、数据类型和错误修复

2026 年 11 月更新

JSON(JavaScript Object Notation)是一种表示结构化数据的纯文本格式。它最初只是 JavaScript 对象语法的一个子集,如今几乎所有编程语言都能读写 JSON,它也成了 Web API、许多配置文件和无数数据导出的默认格式。JSON 的规则一页纸就能写完,但只要犯一个小错,比如多了一个逗号或用错了引号,整个文档就无法被程序读取。本文介绍 JSON 的规则、数据类型、最常见的错误以及修复方法。

JSON 长什么样

一个 JSON 文档就是一个值。这个值通常是用花括号括起来的对象,或者用方括号括起来的数组,里面再包含其他值:

{"name": "王小明", "age": 31, "languages": ["中文", "英语"], "manager": null}

规则很简单:

  • 对象在 { } 中存放“名称–值”对。名称(键)是用双引号括起来的字符串,后面跟一个冒号和值。
  • 数组在 [ ] 中按顺序存放一组值。同一个数组里可以混合不同类型的值。
  • 各项之间用逗号分隔,最后一项后面不加逗号。
  • 字符串只能用双引号。在字符串内部,双引号写作 \",反斜杠写作 \\,换行写作 \n。
  • 各项之间的空格、制表符和换行都会被忽略,所以同样的数据既可以写成一行,也可以分成多行。
  • 没有注释、变量和函数。JSON 只表示数据。

JSON 由内容一致的两个标准定义:ECMA-404 和 RFC 8259。RFC 8259 还规定,在系统之间交换的 JSON 必须使用 UTF-8 编码,因此中文、日本語、한국어 和表情符号都可以直接写进去。

六种数据类型

类型示例规则
字符串"北京"、"caf\u00e9"只能用双引号,可以使用 \u 转义
数字42、-3.5、1.2e6不能有前导零、开头的 +、十六进制、NaN 或 Infinity
布尔值true、false只能小写
空值null表示“没有值”,只能小写
对象{"id": 7}键是字符串,且不应重复
数组[1, "two", false]有顺序,类型可以混合

也要注意 JSON 缺少什么。它没有日期类型:日期通常存成 "2026-11-05T14:30:00Z" 这样的 ISO 8601 字符串,或者存成 Unix 时间戳,两者在 Unix 时间指南中都有介绍。它也没有单独的整数类型,包括 JavaScript 在内的许多解析器都把所有数字存为 64 位浮点数。因此,大于 9,007,199,254,740,991 的整数可能会悄悄改变:JavaScript 会把 {"id": 9007199254740993} 读成 9007199254740992。这就是很多接口把大 ID 当作字符串传递的原因。

JavaScript 的 JSON.stringify 也会悄悄改掉 JSON 无法表示的值:值为 undefined 的属性会被丢弃,NaN 和 Infinity 会变成 null。

常见错误及修复方法

JSON 解析器非常严格,只要有一处错误,整个文档就会被拒绝。错误信息会给出位置,但这个位置往往在真正的问题之后一点。比如多余的结尾逗号,报错的位置是它后面的那个右括号。最常见的错误如下:

问题错误写法正确写法
结尾多余的逗号{"a": 1, "b": 2,}{"a": 1, "b": 2}
单引号{'name': '小明'}{"name": "小明"}
键没有引号{name: "小明"}{"name": "小明"}
注释{"port": 8080 // 开发用}{"port": 8080}
缺少逗号[1, 2 3][1, 2, 3]
Python 风格的值{"ok": True, "x": None}{"ok": true, "x": null}
前导零{"code": 007}{"code": "007"}
未转义的反斜杠{"path": "C:\Users\ming"}{"path": "C:\\Users\\ming"}
字符串里直接换行在引号内按了回车键"第一行\n第二行"
JavaScript 特有的值{"x": undefined}{"x": null}

有些错误的来源很明确。看到单引号、True 或 None,通常是有人直接打印了 Python 字典,而没有用 json.dumps 序列化:输出看起来像 JSON,其实不是。注释和结尾逗号往往来自用 JSONC 或 JSON5 写的配置文件,它们是部分工具接受的宽松变体,比如 VS Code 的 settings.json 和 TypeScript 的 tsconfig.json,但标准解析器两者都会拒绝。如果需要在纯 JSON 中留个说明,可以加一个普通字段,比如 "_comment"。

找错最快的方法,是把文档粘贴到 JSON 格式化工具中。它会在你输入时实时检查,显示第一个错误所在的行和列,点击格式按钮还会直接跳到出错的位置。

格式化与压缩

由于各项之间的空白会被忽略,同样的数据可以有两种写法。格式化(pretty-print)的 JSON 每个值占一行,嵌套的值会缩进,结构一目了然。压缩(minify)的 JSON 去掉了所有不必要的空格和换行。像 {"id": 1042, "name": "王小明", "roles": ["editor", "admin"]} 这样一条数据,压缩后是 57 字节,用两个空格缩进格式化后是 83 字节,但两者包含的数据完全相同。

格式化压缩
适合用于阅读、调试、配置文件、代码评审API 响应、存储、嵌入其他文本
大小较大,嵌套越深,缩进越多尽可能小
版本控制改动按行显示只有一行,改一点整行都变

在网络传输中,两者的差距没有看上去那么大,因为服务器通常会用 gzip 或 Brotli 压缩响应,而重复的空格压缩效果非常好。比较实用的做法是:存储和传输时用压缩的 JSON,需要人阅读时再格式化。

JSON 与 CSV 的区别

CSV(逗号分隔值)是另一种常用的数据交换格式,尤其适合与电子表格打交道。把同样两条记录分别写成两种格式:JSON 是 [{"name": "小明", "city": "上海", "score": 92}, {"name": "Leo", "city": "Lyon", "score": 87}];CSV 则先是一行表头 name,city,score,然后每条记录一行:小明,上海,92 和 Leo,Lyon,87。

JSONCSV
结构嵌套的对象和数组只有行和列的平面表格
类型字符串、数字、布尔值、null全是文本,由读取方推断
字段名每个对象里重复出现只在表头出现一次
表格类数据的大小较大较小
常用打开方式代码编辑器、浏览器、APIExcel、WPS 表格、数据库

简单的判断标准:如果数据天然适合放进电子表格,而且大家会用 Excel 打开,就用 CSV;如果数据有嵌套部分(比如一个客户有多个地址)、需要真正的数据类型,或者要在程序之间传递,就用 JSON。也要留意 CSV 的弱点:包含逗号的值必须加引号;电子表格软件还可能把很长的数字(比如 18 位身份证号)显示成科学计数法,或者去掉 0755 这类区号开头的 0。CSV ⇄ JSON 转换器在两个方向上都能正确处理引号,嵌套的值会以 JSON 文本的形式写进同一个单元格。

哪里会用到 JSON

  • Web API。大多数 REST API 都用 JSON 收发数据,并带上 Content-Type: application/json 请求头。在浏览器开发者工具的“网络”面板里就能看到这些响应。
  • 配置文件。JavaScript 项目的 package.json、PHP 的 composer.json,以及许多应用的设置文件都是 JSON。
  • 登录令牌。JSON Web Token(JWT)把小的 JSON 对象用 Base64url 编码后携带。这也是令牌几乎总以 eyJ 开头的原因:{" 后面跟一个字母,编码后就是这个样子。用 JWT 解码器可以把令牌还原成可读的 JSON。
  • 日志和导出。JSON Lines 文件(.jsonl)每行一个 JSON 对象,因此超大的文件也能逐行处理。
  • 数据库和浏览器。PostgreSQL 有 json 和 jsonb 列类型,网页应用也常把设置转成 JSON 字符串保存在本地存储中。

在代码中读写 JSON

语言文本 → 数据数据 → 文本
JavaScriptJSON.parse(text)JSON.stringify(data, null, 2)
Pythonjson.loads(text)json.dumps(data, indent=2, ensure_ascii=False)
PHPjson_decode($text, true)json_encode($data, JSON_PRETTY_PRINT)

在 Python 中加上 ensure_ascii=False,“北京”这样的中文就会原样输出,而不是变成 \u5317\u4eac。另外,Python 的 json 模块默认会读写 NaN 和 Infinity,而其他解析器会拒绝它们;如果输出要交给其他系统,请给 json.dumps 传入 allow_nan=False。

相关工具