JSONC 就是允许写注释(// 和 /* */)的 JSON,能不能带尾逗号要看解析器。VS Code 的设置文件和 TypeScript 的 tsconfig.json 用的都是它。JSON5 则是按 ECMAScript 5.1 放宽语法的 JSON 超集:键名可以不加引号,字符串可以用单引号,还支持尾逗号、十六进制数字和注释。
两者都不能直接交给 JSON.parse 或 Python 的 json.loads,遇到第一处注释或其他非 JSON 语法就会报错。下面依次讲:怎么判断文件属于哪种格式、报错长什么样、怎么转成标准 JSON。
JSON、JSONC、JSON5 区别对照
| 特性 | JSON(RFC 8259) | JSONC | JSON5 |
|---|---|---|---|
// 与 /* */ 注释 | 不支持 | 支持 | 支持 |
| 尾逗号 | 不支持 | 视解析器而定(见下文) | 支持,每个对象或数组末尾一个 |
| 不加引号的键名 | 不支持 | 不支持 | 支持 |
| 单引号字符串 | 不支持 | 不支持 | 支持 |
| 字符串跨行(转义换行符) | 不支持 | 不支持 | 支持 |
十六进制数字(0x1F) | 不支持 | 不支持 | 支持 |
.5、5.、前导 + | 不支持 | 不支持 | 支持 |
Infinity、NaN | 不支持 | 不支持 | 支持 |
二进制数字(0b101) | 不支持 | 不支持 | 不支持 |
| 规范 | RFC 8259 / ECMA-404 | 没有正式标准,事实上由 VS Code 和 jsonc-parser 定义 | JSON5 规范 1.0.0 |
内置 JSON.parse / json.loads 能否读取 | 能 | 不能 | 不能 |
出处:JSON5 规范、VS Code 的 JSON 文档、RFC 8259。二进制一行是实测:用 json5 2.2.3 执行 JSON5.parse('{a: 0b101}'),报错 JSON5: invalid character 'b' at 1:6。
一句话区分:JSON5 写起来像 JavaScript 对象字面量;JSONC 仍是 JSON,只是容得下注释,键名和字符串照样必须用双引号。
JSON5 文件 config.json5:
// 开发环境配置
{
name: 'go-tools',
port: 0x1F90, // 十六进制的 8080
tags: ['json', 'json5',],
}
JSONC 文件 tsconfig.json:
{
// 开启严格类型检查
"compilerOptions": {
"strict": true,
"target": "ES2022", /* 输出现代语法 */
},
"include": ["src"],
}
JSONC 的尾逗号:各解析器表现不一
JSONC 没有官方规范。它是微软为 VS Code 配置文件非正式引入的格式,同时发布了解析器 jsonc-parser。社区在 jsonc.org 起草了一份规范(仍是草案),对尾逗号只写了一句「解析器可以(MAY)支持」。实际工具的表现如下:
| 解析器 / 工具 | 尾逗号 | 依据 |
|---|---|---|
| VS Code 的 JSON with Comments 模式 | 接受,但会给出警告 | VS Code 文档 |
jsonc-parser 3.3.1,默认选项 | 记为 PropertyNameExpected / ValueExpected 错误,但照样返回解析结果 | 下文实测 |
jsonc-parser 3.3.1,allowTrailingComma: true | 接受 | 下文实测 |
TypeScript 5.9.3(tsc -p) | 接受 | 用上面的 tsconfig 实测 |
Deno(deno.jsonc) | 接受 | Deno 配置文档 |
如果文件要给多种 JSONC 解析器读,最稳妥的做法是不写尾逗号。
你手上的文件是哪种格式
只看扩展名不够:扩展名是 .json 的文件,也可能按 JSONC 或 JSON5 解析。先查下表,再看读取它的那个工具的文档。
| 文件 | 格式 | 说明 | 依据 |
|---|---|---|---|
tsconfig.json、jsconfig.json、tsconfig.*.json | JSONC | VS Code 以 JSONC 模式打开;tsc 5.9.3 接受注释和尾逗号 | VS Code 源码(typescript-basics 扩展)、实测 |
.vscode/settings.json、tasks.json、launch.json | JSONC | 文档点名的 JSON with Comments 文件 | VS Code 文档 |
devcontainer.json | JSONC | 规范原文:「a JSON with Comments file」 | Dev Container 规范 |
deno.jsonc | JSONC | 文档说明:用 deno.jsonc 可以写注释和尾逗号 | Deno 文档 |
babel.config.json、.babelrc.json | JSON5(扩展名虽是 .json) | Babel 按 JSON5 解析;VS Code 按 JSONC 高亮 | Babel 文档、VS Code 源码 |
renovate.json5、.renovaterc.json5 | JSON5 | renovate.json 也接受 JSONC | Renovate 文档 |
其他 *.json5 文件 | JSON5 | — | — |
package.json | 严格 JSON | npm 文档原文:「It must be actual JSON, not just a JavaScript object literal.」 | npm 文档、实测 |
注意:Babel 不认 babel.config.json5 这个文件名,.json5 不在它文档列出的扩展名里;它按 JSON5 解析的,正是 .json 结尾的那两个文件。
报错原文对照
我们准备了两个小文件,分别交给各个运行时。comment.json 带一行注释:
{
// 开发服务器端口
"port": 8080
}
trailing.json 带一个尾逗号:
{
"port": 8080,
}
Node.js 26.10.0 的 JSON.parse(Chrome Headless Shell 156 同样基于 V8,输出一字不差):
comment.json -> SyntaxError: Expected property name or '}' in JSON at position 4 (line 2 column 3)
trailing.json -> SyntaxError: Expected double-quoted property name in JSON at position 18 (line 3 column 1)
Python 3.13.5 的 json.loads:
comment.json -> json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 2 column 3 (char 4)
trailing.json -> json.decoder.JSONDecodeError: Illegal trailing comma before end of object: line 2 column 15 (char 16)
jq 1.7:
comment.json -> jq: parse error: Invalid numeric literal at line 2, column 5
trailing.json -> jq: parse error: Expected another key-value pair at line 3, column 1
npm 11.19.1,package.json 里加了一行 // comment:
npm error code EJSONPARSE
npm error JSON.parse Invalid package.json: JSONParseError: Expected property name or '}' in JSON at position 4 (line 2 column 3) while parsing near "{\n // comment\n \"name\":..."
npm error JSON.parse Failed to parse JSON data.
npm error JSON.parse Note: package.json must be actual JSON, not just JavaScript.
怎么读这些报错:
position 4 (line 2 column 3)指向注释的第一个/。 报错位置正好落在以//或/*开头的那一行,基本可以断定文件是 JSONC 或 JSON5。- 遇到尾逗号时,V8 和 Python 指的位置不同。 V8 报在收尾的
}(第 3 行),Python 3.13.5 直接报在逗号上(第 2 行第 15 列)。其他版本的措辞可能不同,上面是这几个版本的原文。 - 如果报错引号里的字符看不见,比如 Node 26 的
Unexpected token '', "{}" is not valid JSON(两处引号里其实都有一个不可见的 U+FEFF),问题多半不是注释,而是文件开头的 BOM(字节顺序标记)。排查方法见UTF-8 BOM 导致 JSON 解析报错。
JSONC、JSON5 转标准 JSON
转换会丢掉所有注释,因为 JSON 里没有地方放它们。带注释的文件留作源文件,转出来的 .json 当构建产物看待。
Node.js:用 json5 把 JSON5 转成 JSON
// json5-to-json.mjs(先执行 npm install json5)
import { readFileSync, writeFileSync } from 'node:fs';
import JSON5 from 'json5';
const data = JSON5.parse(readFileSync('config.json5', 'utf8'));
writeFileSync('config.json', JSON.stringify(data, null, 2) + '\n');
用 json5 2.2.3 处理上面的 config.json5,得到的 config.json:
{
"name": "go-tools",
"port": 8080,
"tags": [
"json",
"json5"
]
}
Node.js:用 jsonc-parser 把 JSONC 转成 JSON
jsonc-parser 是微软出的 JSONC 解析器。它的 parse() 遇到语法错误不抛异常:问题都记进 errors 数组,同时尽量返回一个结果。所以必须自己检查这个数组:
// jsonc-to-json.mjs(先执行 npm install jsonc-parser)
import { readFileSync } from 'node:fs';
import { parse, printParseErrorCode } from 'jsonc-parser';
const errors = [];
const data = parse(readFileSync('tsconfig.json', 'utf8'), errors, {
allowTrailingComma: true,
});
if (errors.length > 0) {
for (const e of errors) console.error(printParseErrorCode(e.error), 'at offset', e.offset);
process.exit(1);
}
console.log(JSON.stringify(data, null, 2));
用 jsonc-parser 3.3.1 处理上面的 tsconfig.json,输出干净的 JSON,退出码 0。去掉 allowTrailingComma: true 再跑一遍,同一个文件会在偏移量 98 和 123(即两个尾逗号之后紧跟的 })各报一次 PropertyNameExpected 和 ValueExpected。
Python:用 json5 包
标准库 json 没有允许注释的选项。第三方包 json5 能读 JSON5,也就能读 JSONC,因为注释和尾逗号在 JSON5 里都合法:
# 先执行 pip install json5
import json
import json5
with open("tsconfig.json", encoding="utf-8") as f:
data = json5.load(f)
print(json.dumps(data, indent=2, ensure_ascii=False))
在 Python 3.13.5 + json5 0.17.3 下实测,输出与 Node 版相同。
命令行:json5 CLI
npm 包 json5 自带命令行工具,能转换也能校验,读 JSONC 文件同样可以:
npx json5 config.json5 # 输出压缩的 JSON 到标准输出
npx json5 -s 2 -o config.json config.json5 # 缩进 2 格,写入文件
npx json5 -v tsconfig.json # 只校验;有语法错误时退出码为 1
-v 遇到语法错误会以退出码 1 结束,所以这条命令可以直接放进 CI,检查手工维护的 JSON5 或 JSONC 文件。
jq 帮不上忙:前面已经看到,jq 1.7 遇到第一个注释就停了。
小心 Infinity 和 NaN
JSON5 允许写 Infinity 和 NaN,JSON 却表示不了它们。Node 和 Python 的处理方式还不一样:
JSON.stringify(JSON5.parse('{a: Infinity, b: NaN}'));
// '{"a":null,"b":null}'(悄悄变成了 null)
json.dumps(json5.loads('{a: Infinity, b: NaN}'))
# '{"a": Infinity, "b": NaN}'(输出的已经不是合法 JSON)
json.dumps(json5.loads('{a: Infinity}'), allow_nan=False)
# ValueError: Out of range float values are not JSON compliant: inf
如果 JSON5 文件里可能出现这两个值,Python 端加上 allow_nan=False,或者转换前先检查。另外,JSON5 的单引号字符串里如果有 " 或反斜杠,JSON.stringify 会重新转义,规则见 JSON 字符串转义完全指南。
转完之后校验一遍
转换结果可以粘贴到 JSON 格式化工具里校验并美化,全程在浏览器本地运行。
注意:这个工具只接受严格 JSON。它用浏览器的 JSON.parse 解析,直接粘贴 JSONC 或 JSON5 只会得到一条语法错误,并标出解析中断的行和列。先转换,再校验。
什么时候不该用 JSONC 或 JSON5
- API 传输和数据交换。 RFC 8259 规定 JSON 生成器的输出「MUST strictly conform to the JSON grammar」(必须严格符合 JSON 语法)。接收方通常就是
JSON.parse或json.loads,两者都不认注释。 package.json。 npm 只接受严格 JSON,写一行注释,npm run这类命令就会报EJSONPARSE。- 会被别的工具读取的文件。 Node 的
require('./tsconfig.json')走的是严格 JSON 解析,读带注释的 tsconfig 会直接失败(SyntaxError: …tsconfig.json: Expected property name or '}' in JSON at position 4)。凡是脚本要读的 JSONC 文件,脚本里都得换成 JSONC 解析器。 - 悄悄写进了注释的
.json文件。 Renovate 文档建议用.jsonc文件,而不是在.json文件里写注释,理由是后者「can cause issues with editors and syntax highlighting」(可能导致编辑器和语法高亮出问题)。扩展名写明格式,每个工具都知道该怎么读。
如果是从头挑配置格式,又希望到处都能写注释,TOML 和 YAML 原生就支持注释,对比见 TOML、JSON、YAML 配置格式对比。
常见问题
JSON5 和 JSONC 有什么区别?
JSONC 是标准 JSON 加上 // 和 /* */ 注释,尾逗号视解析器而定。JSON5 走得更远,引入 ES5.1 语法:键名免引号、单引号字符串、十六进制数字、Infinity/NaN、尾逗号。合法的 JSONC 文件通常也是合法的 JSON5,反过来不成立。
JSON5 或 JSONC 可以用于生产环境 API 吗?
不建议。它们适合人手工维护的配置文件,网络上传输的数据应使用严格 JSON(RFC 8259)。客户端一般用 JSON.parse 或 json.loads 解析响应,注释、免引号键名和尾逗号都会被拒绝。
VS Code 原生支持 JSON5 吗?
不支持。VS Code 内置的 JSON 扩展注册了 json、jsonc、jsonl 等语言,但没有 json5,所以 .json5 文件要装扩展市场里的插件才有高亮。JSONC 是内置的:设置文件、tasks.json、launch.json 和 tsconfig.json 都以 JSON with Comments 模式打开。
如何将 JSON5 转换为标准 JSON?
命令行执行 npx json5 -s 2 -o config.json config.json5;代码里用 JSON.stringify(JSON5.parse(text), null, 2)。注释会被丢弃。转换前先检查有没有 Infinity 和 NaN,JSON.stringify 会把它们变成 null。
tsconfig.json 可以写注释和尾逗号吗?
对 TypeScript 本身来说可以:我们用 tsc 5.9.3 实测,两者都能通过,VS Code 也以 JSONC 模式打开 tsconfig。但用 JSON.parse 或 require() 读 tsconfig 的脚本会在注释处报错,这类脚本需要换成 JSONC 解析器。
JSONC 就是 JSON with Comments 吗?
是的。「JSON with Comments」是 VS Code 里这种语言模式的名称,jsonc 是它的语言 ID 和文件扩展名。它没有正式标准,jsonc.org 上有一份社区草案,以 jsonc-parser 默认配置下接受的语法为准。
更多浏览器端开发者工具,见开发者工具必备指南。