你写了一段看上去完全合理的 JSON —— 每个 key 都加了引号,每个值都合法 —— JSON.parse() 还是抛了一个 SyntaxError。元凶几乎总是尾随逗号:对象或数组最后一项后面那个多余的 ,。本文讲清楚 JSON 为什么不允许它、它从哪儿溜进来,以及怎么把它清掉。
什么是尾随逗号?
尾随逗号(也叫「悬挂逗号」或「最终逗号」)是出现在列表 最后 一项之后的逗号 —— 在闭括号之前没有任何东西跟着它。
// 对象里的尾随逗号
{
"name": "Ada",
"score": 98, // ← 这个逗号没有下一项
}
// 数组里的尾随逗号
[1, 2, 3,]
// ^ 同样的问题 上面两个例子传给 JSON.parse() 都会抛 SyntaxError。
JSON 为什么不允许尾随逗号?
JSON 语法(定义在 RFC 8259)规定逗号是元素之间的 分隔符 —— 它两边都必须有值。JSON 对象的形式规则长这样:
object = "{" [ member *( "," member ) ] "}"
member = string ":" value 逗号后面必须紧跟另 一个 member。如果逗号后没东西,语法就非法了。这是一个刻意的设计选择:JSON 把简单性和解析无歧义放在开发者便利性之前。
JavaScript 走了另一条路。ES5(2009)明确把数组字面量里的尾随逗号变成合法,ES2017 把它扩展到函数参数。JS 里的尾随逗号现在是常规风格 —— 很多 linter 甚至会强制要求,因为往列表里加一项时它能产出更干净的 git diff。
JavaScript 允许的东西和 JSON 允许的东西之间的这道鸿沟,是你能遇到的几乎所有尾随逗号错误的根源。
尾随逗号都从哪儿来
手工编辑的配置文件
像 tsconfig.json、package.json 或者应用设置这类配置文件是人在编辑。加了或删了一条之后,很容易留下一个孤逗号。很多编辑器(VS Code、WebStorm)默默接受 JSONC(带注释的 JSON),它允许尾随逗号,所以文件在编辑器里看起来没事,但在运行时就崩了。
// 你删了 "debug": true 但忘记删那个逗号
{
"compilerOptions": {
"strict": true,
"target": "ES2020", // ← 现在变成了尾随
}
}JavaScript → JSON 序列化
开发者有时会手工把 JavaScript 值拼成一段 JSON 字符串,或者用 Array.join(',')。如果逻辑无条件地在每一项后面加逗号,最后一项就会拖一个尾随逗号。
// ❌ 朴素的手工序列化
const parts = items.map(item => `"${item.name}": ${item.value}`);
const json = '{' + parts.join(',') + ',}'; // } 前面多了个逗号
// ✅ 用 JSON.stringify —— 它总是产出合法 JSON
const json = JSON.stringify(Object.fromEntries(items.map(i => [i.name, i.value])));LLM 和 AI 输出
语言模型被要求「输出 JSON」时经常会产出尾随逗号。模型在 训练时见过海量的 JavaScript 代码,那里尾随逗号是合法的,所以它复制了这个模式。在解析 AI 生成的 JSON 前一定要做校验或修复。
从 JavaScript 源码里复制粘贴
从一个 .js 或 .ts 文件里复制一段对象字面量、粘到 JSON 环境里,是尾随逗号最常出现的途径之一。源代码是合法 JavaScript;目的地只接受 JSON。
怎么找到尾随逗号
错误信息通常会指向接近问题的位置,但不一定精确指到逗号本身 —— parser 是在撞上意外的 } 或 ] 时才意识到不对劲:
SyntaxError: Expected double-quoted property name in JSON at position 58
// 或者
SyntaxError: Unexpected token '}', ..."score": 98,}" is not valid JSON从报错的位置往回找。尾随逗号就是触发错误的那个闭括号前面紧邻的那个字符。
对大 JSON 文件,一个正则搜索能帮上忙:
// 找出对象/数组里的尾随逗号
,\s*[}\]]怎么修
选项 1 —— 手动删掉它
找到出问题的那个对象或数组的最后一项,把它后面的逗号删掉。小文件这是最快的办法。
选项 2 —— 用正则替换(小心)
const fixed = raw.replace(/,\s*([}\]])/g, '$1');
JSON.parse(fixed); 对常见情况能用,但很脆弱:它会破坏内含字面字符 ,} 或 ,] 的字符串。只有在你确定输入里没有这种字符串时才用它。
选项 3 —— 用一个正规的修复 parser
修复 parser 理解完整的 JSON 语法,它只在结构上非法的位置把尾随逗号去掉,不动字符串内容。这是生产代码或不可信输入下最安全的做法。
选项 4 —— 配置文件改用 JSONC
如果尾随逗号出现在你能控制的配置文件里,可以考虑改用支持 JSONC(带 注释的 JSON)的 parser。TypeScript 的 tsconfig.json 已经用 JSONC。Node.js 配置文件里,像 @humanwhocodes/momoa 或 json5 这样的库能解析允许尾随逗号和注释的 JSON 超集。
什么时候尾随逗号其实被允许:JSONC 与 JSON5
有两种和 JSON 相邻的格式专门允许尾随逗号(以及其他一些放宽),值得认识一下:
- JSONC(带注释的 JSON) —— 被
tsconfig.json、VS Code 的settings.json以及很多其他开发者配置使用。JSONC 允许////* */注释 以及 尾随逗号。文件还是叫.json,但标准JSON.parse()会拒绝它 —— VS Code 和相关工具自带 JSONC 感知的 parser。 - JSON5 —— 更完整的超集:注释、尾随逗号、不带引号的 key、单引号、多行字符串、十六进制数字。用
json5npm 包或 Python 的pyjson5来 opt-in。适合人手编辑、你能控制 parser 的场景;不要把它通过 API 发给期待严格 JSON 的客户端。
一条经验法则:尾随逗号要 排除 在任何会跨过严格 JSON parser 的东西之外(API 响应、请求体、被随便哪个库消费的文件),只在 JSONC/JSON5 里、且消费方知情的前提下拥抱它们。
预防尾随逗号
- 永远别手工拼 JSON 字符串。 用
JSON.stringify()—— 它总是产出符合规范的输出。 - 加一条 linter 规则。 ESLint 的
jsonc/no-trailing-commas规则会在保存.json文件时抓出尾随逗号。 - 校验 AI 输出。 在使用语言模型生成的任何东西前,先跑一遍
JSON.parse()(或一个修复 parser)。 - 用 Prettier。 Prettier 会重新格式化 JSON 文件, 并在保存时自动去掉尾随逗号。
常见问题
JSON 允许尾随逗号吗?
不允许。RFC 8259 里的 JSON 语法把逗号严格定义成两个值之间的分隔符,所以一个后面在闭括号 } 或 ] 之前什么都没有的逗号是非法的。每一个标准 parser —— JSON.parse()、Python 的 json 模块、Go 的 encoding/json —— 都会拒绝它。
我怎么从 JSON 里去掉一个尾随逗号?
如果只有一个文件,手动把最后一项后面的逗号删了。需要反复或程序化处理时,用 JSON.stringify() 重新生成 JSON,或者用一个修复 parser,或者用 JSON Fix 这样的工具 —— 它会去掉结构上的尾随逗号而不动字符串内容。
为什么 JavaScript 允许尾随逗号,JSON 却不允许?
JavaScript 在 ES5(数组)和 ES2017(函数参数)里加入了尾随逗号,作为开发者便利特性,能产出更干净的 git diff。JSON 是一种刻意极简的交换格式,把解析无歧义放在便利之前,所以从未接纳它。完整差异见 JSON vs JavaScript 对象。
尾随逗号会引发什么错?
通常是 SyntaxError: Unexpected token '}' 或 Expected double-quoted property name in JSON,因为 parser 在逗号后期待另一个值,结果撞上了闭括号。这是更广义的 JSON.parse「Unexpected token」错误 的一种变体。
立刻修 —— 无需任何配置
如果你手里有一段带尾随逗号的 JSON、现在就要修好,JSON Fix 会自动去掉它们,连带其他常见问题一并处理 —— 单引号、不带引号的 key、Python 字面量、JavaScript 注释。把你的 JSON 贴进去、点 Repair & Format,然后把干净的 JSON 拷回来。无需账号、不上传、数据不离开你的浏览器。
- JSON Fix —— 修复尾随逗号以及其他常见 JSON 错误
- 修复「[object Object] is not valid JSON」以及其他语法错误 —— JSON 语法错误的完整指南
- 修复 JSON 里的尾随逗号 —— 含坏例和好例的速查指南
- JSON Diff —— 对比原始与修复后的 JSON,确认修复没问题