JSON 是从哪来的
JSON 全称 JavaScript Object Notation。2001 年前后,Douglas Crockford 把 JavaScript 里"写对象"的那套字面量语法单独拎出来, 做成一种与语言无关的数据交换格式——只借语法,不借 JavaScript 的任何行为。 后来它被 ECMA-404 和 RFC 8259 收成正式标准,如今几乎每种语言都自带解析库。
它流行起来的原因很朴素:文本格式,人能读,机器也好读。同样一件事用二进制协议表达,调试前得先找个工具; 用 JSON 表达,肉眼就能看出字段名和值。配置文件、接口返回、日志、缓存里到处都有它。
为什么接口和日志里的 JSON 都压成一行
- 一条记录一行。日志按行切分,"一行一条 JSON"(也就是常说的 NDJSON)可以直接流式处理:读一行、解析一行、写一行。一条记录自己带几十个换行,按行读的管道立刻就乱套。
- 省体积。缩进和换行不携带任何信息,字段名重复几百万次,空格也跟着重复几百万次。
- 少一层转义麻烦。多行文本塞进某些传输格式还得再转义一次,压成一行就没这个问题。
另外可以放心:压缩只动结构上的空白,字符串里的内容一个字节都不会变。
最常见的几个语法坑
- 最后一个元素后面不能有逗号。
{"a":1,"b":2,}和[1,2,3,]都是错的。JavaScript 的对象字面量允许这种多余逗号,JSON 不允许——从 JS 代码里复制数据时,这是最常见的翻车点。 - 键名必须用双引号。
{name:"x"}不合法,{"name":"x"}才合法;用单引号同样不合法。 - 不能有注释。// 和 /* */ 都会被当成语法错误。非要留说明,只能自己加一个 "_comment" 字段,并且说好别让程序把它当数据用。
- 没有 undefined、NaN、Infinity。这三个值在 JSON 里都不存在,要么给个具体数字,要么写 null。
- 零碎的还有:数字不能有前导零(
01要写成1)、不能写.5或1.、字符串里不能直接换行、\u后面必须跟满 4 位十六进制。
看起来像 JSON,其实不是 JSON
- JavaScript 对象字面量:键名没引号、值里有函数或 undefined、带注释、带尾逗号——那是代码片段,不是 JSON。
- JSON5 / JSONC / HJSON:JSON 的宽松版,允许注释和尾逗号,多用于配置文件;喂给
JSON.parse一样报错。 - Python 的 dict 打印结果:
{'a': 1, 'b': None, 'c': True},单引号、None、True 都是 Python 的写法。 - NDJSON:整个文件是"每行一个 JSON 对象",单看全文不是合法 JSON,要按行拆开逐个解析。
- 前后带料:JSONP 外面裹着 callback(...);有的接口在前面加了防劫持前缀;记事本另存的文件开头可能藏着一个看不见的 UTF-8 BOM。这些东西都会让解析器在第一行就翻脸。
它和 JavaScript 对象字面量差在哪
一句话:JSON 是文本,对象字面量是代码。JSON 只能描述数据,字面量还能写逻辑。
具体差别:键名只能是双引号字符串;没有 undefined、函数、正则、日期(时间一般约定写成 ISO 8601 字符串,取到后自己转 Date);
不支持注释、尾逗号、单引号、十六进制数字;JSON.parse 只产出纯数据、不会执行任何东西,所以取数据请用它,别用 eval。
怎么用这个工具
- 粘进内容,点四个按钮里的任意一个:2 空格缩进、4 空格缩进、压缩成一行、键名按字母排序。
- 语法有问题时,结果区会告诉你第几行第几列,把那一行原文贴出来,并用
^标在出错的那一列上,下面再附上浏览器的原始报错。 - 输入是空的、或者顶层是个裸值(比如
123、"abc"),都能正常处理,不会报错。
本工具完全在你的浏览器里运行,粘贴的内容不会发送到任何服务器,也不会被保存。关掉页面就没了。