JSON 解析与处理库选型对照
结论:原生 API 最快,容错解析带偏移量,路径查询与补丁各管一段。选型看三件事:错误定位、是否破坏原文、边界是否明确。

结论:先按用途分四类再看实现——只读值用原生 JSON.parse,需要偏移量或保留原文格式用 jsonc-parser,查询与补丁库各自按需引入;体积大的库按页面动态导入,长期不维护的库直接排除。
每个库都宣称自己「快、小、全」。真正区分它们的是出错时能告诉你多少信息。
一、按用途分四类
| 类别 | 代表库 | 解决什么 |
|---|---|---|
| 标准解析 | JSON.parse / JSON.stringify |
语法 ↔ 对象,速度优先 |
| 容错解析 + 编辑 | jsonc-parser、json5 |
带注释的输入、精确到偏移量的错误、保留格式的修改 |
| 查询 | jsonpath-plus、jsonpath |
按表达式筛选节点 |
| 变更 | fast-json-patch、immer |
生成/应用补丁,不可变更新 |
先确定自己在哪一类,再比较具体实现,否则很容易拿查询库去干解析的活。
二、横向对照
| 库 | 错误定位 | 容错(注释/尾逗号) | 能否保留原文格式 | 适用场景 |
|---|---|---|---|---|
JSON.parse |
只有消息与位置(引擎相关) | ✗ | ✗ | 默认解析、接口数据 |
jsonc-parser |
精确 offset + 错误码 |
✓ | ✓(modify + applyEdits) |
编辑器、配置文件 |
json5 |
行列信息 | ✓(更宽松) | ✗ | 读取 JSON5 配置 |
jsonlint |
行列信息 | ✗ | ✗ | 仅作参考,维护不活跃 |
jsonpath-plus |
表达式语法错误 | — | — | 按表达式查询 |
fast-json-patch |
操作级错误 | — | — | 补丁生成与应用 |
lz-string |
— | — | — | 把 JSON 压缩进 URL |
JSON.parse 的错误信息在不同引擎差异很大。V8 会给出类似
Unexpected token } in JSON at position 42 的提示,但位置是否准确取决于引擎版本;
jsonc-parser 则稳定返回结构化的 { error, offset, length },适合做编辑器标记。
三、四个关键决策点
3.1 需不需要偏移量
做编辑器、要做「点错误跳转到对应行」就必须有 offset。判断方法很简单: 如果你的错误提示只能打印「JSON 格式错误」,用户就得自己找半天。
import { parse, printParseErrorCode } from 'jsonc-parser';
const errors: Array<{ error: number; offset: number; length: number }> = [];
parse(text, errors, { allowTrailingComma: true, disallowComments: false });
if (errors.length > 0) {
const firstError = errors[0];
console.error(`${printParseErrorCode(firstError.error)} at offset ${firstError.offset}`);
}
3.2 要不要保留原文
只想读值 → 任何解析器都行。 要「改一个字段、其余原样保留」→ 必须用编辑式 API,不能用「解析 → 改对象 → 序列化」。
后者会丢掉:注释、键顺序(部分实现)、缩进风格、数字字面量写法(1e3 变 1000)、转义形式(\u4e2d 变中文)。
3.3 边界行为是否明确
选库前查三件事的文档:
- 重复键怎么处理(取最后一个 / 报错);
- 大整数是否丢精度(多数 JS 库会,因为都走
Number); - BOM、注释、尾逗号的支持范围。
没有文档说明的,就写个小样例实测。这比读 README 更可靠。
3.4 维护状态
JSON 库的风险不在功能缺失,而在长期不维护:安全补丁(原型污染、ReDoS)不会有人发。
四、其他语言的对照
| 语言 | 标准库 / 主流库 | 关键差异 |
|---|---|---|
| JavaScript | JSON.parse |
数字一律双精度 |
| TypeScript | 同上 + jsonc-parser / zod |
类型只在编译期 |
| Go | encoding/json |
默认 float64,需 UseNumber() 保精度;json.RawMessage 延迟解析 |
| Java | Jackson / Gson / Moshi | Jackson 需注意默认类型开启的风险 |
| Python | json / orjson |
parse_float=Decimal 保精度;orjson 更快但不支持所有类型 |
| Rust | serde_json |
强类型反序列化;arbitrary_precision 特性保精度 |
| C++ | simdjson / RapidJSON | simdjson 面向解析吞吐,RapidJSON 更通用 |
跨语言交换时,最容易踩的还是数字精度与时间格式,库的选择只能缓解不能消除。
五、典型组合方案
方案 1:工具站(浏览器端)
解析与错误定位:jsonc-parser
编辑器:CodeMirror 6 + @codemirror/lang-json
查询:jsonpath-plus
补丁:fast-json-patch
分享链接:lz-string
这套组合的特点是全在本地跑,不上传数据,符合工具类站点的隐私预期。
方案 2:服务端接口网关
校验:Ajv(schema 编译一次,复用)
解析:原生 JSON.parse(配合 body 大小限制)
大字段延迟解析:保留原始字符串,用时再 parse
网关层不要引入查询/补丁库做业务逻辑,那是业务层的事。
方案 3:CLI 与脚本
取字段:jq
格式转换:yq / dasel
交互浏览:jless
批量校验:ajv-cli
六、体积与性能的实际影响
jsonc-parser体积很小,适合进主包;json5比jsonc-parser略大,因为要支持更多语法;jsonpath-plus包含表达式求值,体积明显更大,应随页面懒加载;fast-json-patch体积中等,只有对比功能时才需要。
优化手段很直接:按页面动态导入,别把它们塞进首屏 chunk。
const { JSONPath } = await import('jsonpath-plus');
七、检查清单
- [ ] 按用途选库,不用查询库做解析;
- [ ] 需要精确错误定位时用
jsonc-parser; - [ ] 需要保留注释与格式时用编辑式 API;
- [ ] 实测重复键、大整数、BOM 三个边界行为;
- [ ] 关注库的维护状态与安全通告;
- [ ] 大体积库按需动态导入。
常见问题
如何按项目规模选择 JSON 库?
小到只读接口数据的工具,用原生 JSON.parse 就够;需要编辑器式错误定位或保留原文格式的中型项目,选 jsonc-parser;服务端网关只做校验与解析,查询和补丁库留给业务层;CLI 与脚本直接用 jq、yq、ajv-cli。按用途分类之后再比较具体实现,能避免拿查询库去干解析的活。
为什么维护状态比功能多寡更值得关注?
JSON 库真正的风险不在功能缺失,而在长期不维护:原型污染、ReDoS 这类安全补丁不会有人发。功能再全,只要维护停摆,出问题时只能自己打补丁。选型时把维护状态与安全通告当成硬指标,比对照功能表更有效。
能否用 JSON.parse 改字段并保留注释与缩进?
不能。「解析 → 改对象 → 序列化」会丢掉注释、键顺序、缩进风格、数字字面量写法(1e3 变 1000)和转义形式(\u4e2d 变中文)。要改一个字段、其余原样保留,必须用 jsonc-parser 的 modify 与 applyEdits 这类编辑式 API。