什么是 JSON Diff?
JSON diff 是对两个 JSON 对象进行比较,识别出每个被添加、删除或值发生变化的键。与文本 diff(逐行比较)不同,JSON diff 理解结构:它通过键匹配对象,通过位置(或键字段)匹配数组,并在语义层面而非字符层面报告变化。
这使得 JSON diff 对开发者来说比将两个 JSON 文件输入 diff 有用得多。如果你只是重新格式化了缩进,文本 diff 会显示整个对象发生了变化。而 JSON diff 忽略格式,专注于数据。

为什么开发者需要 JSON Diff
调试 API 变更
你对后端端点进行了更改,需要确认响应结构完全符合前端预期。比较变更前后的响应,查看发生了什么变化。
检测配置漂移
两个环境(预发布和生产)应具有相同的配置,但出了问题。JSON diff 立即揭示哪些键出现了分歧以及差异有多大。
代码审查
拉取请求更改了 JSON schema、fixture 文件或 package-lock.json。语义 diff 显示有意义的更改,而不会因重新格式化而产生噪音。
回归测试
将预期的 API 响应存储为 JSON fixture。代码更改后,将新响应与 fixture 进行 diff,以捕获非预期的更改。
审计状态变更
在 Redux 或类似的状态管理模式中,记录状态快照并进行 diff,以准确了解哪些操作发生了变化。

差异类型
JSON diff 通常报告三种类型的变更:
新增键
键存在于第二个(新)对象中,但不存在于第一个(旧)对象中:
// 旧
{ "name": "Alice", "role": "admin" }
// 新
{ "name": "Alice", "role": "admin", "email": "alice@example.com" }
// Diff: + "email": "alice@example.com"
删除键
键存在于第一个(旧)对象中,但不存在于第二个(新)对象中:
// 旧
{ "name": "Alice", "legacy_id": 12345 }
// 新
{ "name": "Alice" }
// Diff: - "legacy_id": 12345
修改值
键在两个对象中都存在,但值不同:
// 旧
{ "status": "pending", "retries": 0 }
// 新
{ "status": "complete", "retries": 3 }
// Diff: ~ "status": "pending" → "complete"
// ~ "retries": 0 → 3
嵌套对象 Diff
一个好的 JSON diff 会递归比较嵌套对象:
// 旧
{
"user": {
"name": "Alice",
"address": { "city": "Paris", "country": "FR" }
}
}
// 新
{
"user": {
"name": "Alice",
"address": { "city": "Lyon", "country": "FR" }
}
}
// Diff: ~ user.address.city: "Paris" → "Lyon"
报告完整路径(user.address.city)而不仅仅是键名(city)对于大型、深度嵌套的对象至关重要。
数组 Diff 的挑战
数组比对象更难 diff,因为元素没有固有的标识符。两种策略:

基于索引的 Diff
比较相同数组索引处的元素。简单,但对重新排序敏感:如果在开头插入一个元素,之后的所有内容都会显示为“已更改”。
基于键的 Diff
如果数组元素是具有已知标识符字段(如 id 或 slug)的对象,则先通过该键匹配元素,然后再进行比较。这可以正确处理重新排序、插入和删除。
实际示例
比较 API 响应
// 在变更前后获取数据
const before = await fetch('/api/users/1').then(r => r.json());
// ... 进行你的更改 ...
const after = await fetch('/api/users/1').then(r => r.json());
// 将两者粘贴到 JSON Diff 工具中查看变化
比较 package.json 文件
升级依赖时,对旧的和新的 package.json 进行 diff,可以确认哪些包的版本发生了变化以及添加了哪些新依赖。
比较配置文件
环境通常将配置存储为 JSON。对 config.staging.json 和 config.production.json 进行 diff,可以找出任何应该匹配但不匹配的值。
JSON Diff 与文本 Diff 对比
| 特性 | JSON Diff | 文本 Diff |
|---|---|---|
| 理解结构 | ✅ | ❌ |
| 忽略格式 | ✅ | ❌ |
| 处理键重新排序 | ✅ | ❌ |
| 无需 JSON 知识即可工作 | ❌ | ✅ |
| 适用于非 JSON 内容 | ❌ | ✅ |
| 显示变更键的路径 | ✅ | ❌ |
对于 JSON 内容,始终使用语义化的 JSON diff。将文本 diff 保留给非结构化内容。
如何阅读 Diff 输出
标准 diff 符号:
+(绿色):在新版本中新增-(红色):从旧版本中删除~或无符号(黄色):值已更改- 无变化:键在两个版本中都存在且值相同(通常隐藏以减少噪音)
比较大型 JSON 对象时,使用“隐藏未更改的键”选项,只关注不同的部分。
→ 使用 JSON Diff 工具,将两个 JSON 对象并排粘贴,即可获得即时、结构化的比较结果,突出显示所有变化。