JSON 是从 JavaScript 的对象字面量里抠出来的一个子集,只描述数据结构,不描述类型和语义。 同一批数据比 XML 少 48%,代价是没有注释、没有属性、没有命名空间。
上一节用 XML 传数据,看得出一件事:标签太占地方。这一节看那个把标签全省掉的格式。
一、它从哪来
JavaScript 里写一个对象本来就长这样:{ "a": 1, "b": [2, 3] }。
道格拉斯·克罗克福德看出这段语法本身就能当数据格式用,于是把它单独拎出来,去掉函数、
去掉 undefined、强制键必须加双引号,剩下的就是 JSON。
所以 JSON 不是 JavaScript——它是 JS 字面量的一个子集,
恰好能被 JS 直接 eval(后来改成 JSON.parse,安全得多)。
它的正式规范是 RFC 8259(2017),之前的 RFC 4627、RFC 7159 是前身。
这个出身很关键:它一开始就不是为了「描述文档」,而是为了「描述一个数据结构」。
所以它没有属性、没有命名空间、没有 DTD,这些在 XML 里都有。
二、六种值,就这些
对象 {}、数组 []、字符串 "abc"、数字 12 或 1.5、布尔 true/false、空 null。
就这六种,没有第七种。
Demo 把三条数据分别写成三种形态:RSS 那种 XML 675 字节,JSON 美化版 411 字节,
紧凑版 350 字节——紧凑版比 XML 少 325 字节,省 48%。
少在哪?少在标签。XML 每条要写两遍 title(开一次合一次),JSON 只写一次键名。
三条数据乘下来,一半的字节就省掉了。
还有一个反直觉的点:如果强制把中文转成 \uXXXX(ensure_ascii=True),字节数从 350 涨到 440,
多花 26%。因为一个汉字在 UTF-8 里是 3 字节,转义之后变成 6 字节。
所以发给浏览器时别开这个选项。
三、它不能做什么
不能写注释。规范明确禁止,所以配置文件里想加一句说明只能塞个假字段。
没有属性。XML 里 <book id="b1"> 那种「元数据挂在元素上」的写法,JSON 只能改成多一个键。
没有类型系统。"2026-10-20" 在 JSON 里就是个字符串,它不会知道这是日期。
要区分类型,只能靠字段名或者额外约定。
数字就是 IEEE 754 双精度。
Demo 里 0.1 + 0.2 打出来是 0.30000000000000004——这不是 JSON 的错,是所有浮点的通病,
但用 JSON 传金额时要特别小心,最好传字符串或整数分。
四、动手 Demo:同一批数据,第三种写法
把前面那三条数据写成 JSON 的三种形态(美化、紧凑、强制转义),量字节;和 RSS 那份 XML 对比; 再解析回来验证没有丢信息。最后把六种值类型列成表。
J_COMPACT = json.dumps(DATA, ensure_ascii=False, separators=(',', ':'))
J_ASCII = json.dumps(DATA, ensure_ascii=True, separators=(',', ':'))
print(len(J_COMPACT.encode('utf-8'))) # 350
print(len(J_ASCII.encode('utf-8'))) # 440
print(json.loads(J_COMPACT) == DATA) # True
实跑输出:
--------------------------------------------------------------------
JSON:同一批数据,又一种写法
--------------------------------------------------------------------
RSS 那种 XML 写法 675 字节(3 条)
JSON 美化版 411 字节
JSON 紧凑版 350 字节
JSON 强制转义非 ASCII 440 字节
紧凑版比 XML 少 325 字节,48%
转义非 ASCII 多花 90 字节,26%
紧凑版的样子(前 76 个字节):
[{"title":"图解 HTTP 读完了","url":"https://example.com/p/1","date":"2026-10-20",…
解析回来条数 3 条
第一条的字段 date、desc、title、url
和原数据一致吗 一致
类型 JSON 写法 Python 里对应
对象 { } dict
数组 [ ] list
字符串 "abc" str
数字 12 / 1.5 int / float
布尔 true / false True / False
空 null None
JSON 里不能写注释 是
JSON 里没有属性与命名空间 是
键必须是字符串 是
这三条正好是 XML 擅长的地方,也是 JSON 敢说自己「轻」的原因:
它只描述数据结构,不描述「这是什么类型的数据」「这个字段该怎么处理」。
那些事交给人和文档,协议不管。
0.1 加 0.2 的结果 0.30000000000000004
这一行是提醒:JSON 的数字就是 IEEE 754 双精度,
所以金额之类的东西别拿浮点存——和 JSON 没关系,是所有浮点的通病。
XML 675 字节,JSON 美化版 411,紧凑版 350,省 48%。
差别全在标签上:XML 每个字段要开一次合一次。
强制转义非 ASCII 之后从 350 涨到 440,多花 26%。
因为一个汉字 UTF-8 是 3 字节,转成 \uXXXX 变 6 字节。
json.loads 之后和原数据完全一致——三种写法丢的信息一样多,差别只在字节。
六种值类型表里最需要注意的是「数字」那一行:JSON 只有一种数字,不区分整数和浮点,
所以 12 和 12.0 在某些语言里会被解析成不同类型。
30 秒实验
- 把
ensure_ascii改成True再发一次请求,用开发者工具看响应体大小。 - 把金额改成
19.99,算十次加法,看误差怎么累积。 - 想一想:为什么配置文件(比如 VS Code 的 settings.json)可以接受「不能写注释」这个限制?
常见误区
- 「JSON 是 JavaScript 的一部分」——它是 JS 字面量的子集,但两种语言都能用。
- 「JSON 比 XML 高级」——各有取舍,JSON 省字节但丢了类型和命名空间。
- 「JSON 的数字能精确表示金额」——它就是浮点,金额别用它算。
自测三问(点开对答案)
1. JSON 一共有几种值类型? —— 六种:对象、数组、字符串、数字、布尔、null。 2. JSON 比 XML 省在哪? —— 省在标签:XML 每个字段要开合两次,JSON 只写一次键名。 3. 为什么 `ensure_ascii=True` 会让体积变大? —— 汉字被转成 `\uXXXX`,3 字节变 6 字节。第十章讲完了。最后一章换个角度:前面讲的每一样东西,都能被怎么攻击。
- ☐ (本章完,下一节 11.1.1 HTTP不具备必要的安全功能)