工具
指南

JSON 差异对比

JSON

对比两份 JSON 文档,并高亮结构差异。

100% 客户端 无后端
左侧(原始)
右侧(改动)
输出
本页内容

什么是 JSON Diff?#

JSON Diff 对比两份 JSON 文档,准确地告诉你它们之间到底变了什么——哪些字段冒出来了、哪些字段没了、哪些路径还在但值变了。它是文本 diff 的结构化版本:不是逐行匹配,而是遍历对象和数组这棵树,所以一个值从 1 变成 2,会被精确定位成某个路径上的一处编辑,而不是一整段文本被重写。

只要 JSON 是某种会演进之物的传输格式,这件事就有用:两次部署之间的 API 响应、两次修改之间的配置文件、测试套件里的 fixture、每天导出的数据。两份美化后的文档并排摆着、肉眼比对,只对小文档管用;嵌套一旦深了,你需要的是把差异一条条列出来。

要注意的是,JSON diff 对数组的顺序敏感。两个数组只有在每个位置上的元素都一一相等时才算相等——这是 JSON 本身对相等的定义。所以 [a, b][b, a] 是不同的,diff 会报出来:顺序有意义时(比如一组步骤)这很有用,顺序无意义时(比如一个被塞进数组的集合)会让人意外。

怎么使用#

  1. 把原文档粘进 左侧(原文)(Left (original)),把修改后的文档粘进 右侧(改动后)(Right (changed))。
  2. 边输入边实时比较。你也可以点 比较(Compare)强制刷新一次。
  3. 输出区把每条差异各占一行:
    • Added(新增)——该路径只在右侧存在,行内显示新值。
    • Removed(删除)——该路径只在左侧存在,行内显示旧值。
    • Changed(改动)——两侧都存在但值不同,行内显示 旧 → 新。 每行前面带一个 JSONPath 风格的路径,比如 $.version$.tags[2],方便你定位到任一文档里的对应位置。
  4. 如果两份文档深度相等,状态栏会明确写”无差异”,而不是扔一个空输出区让你自己猜。
  5. 示例(Sample)载入一对真实的”前后”文档;点 清空(Clear)重置两边和结果。

主要特性#

  • 结构化、非文本化。 比较的是解析后的值树,所以重新缩进、调换对象键的顺序、改空白,都不会产生假差异。
  • 路径精确。 每条改动都带 JSONPath 记法的位置——$ 是根,.key 是对象字段,[i] 是数组下标——你可以直接跳到正确位置。
  • 三种改动类型。 新增、删除、改动分开报告并配色,让新增一眼区别于删除和编辑。
  • 分侧报错。 如果某一侧不是合法 JSON,状态栏会点名是哪一侧失败了(左侧输入不是合法 JSON。),而不是抛一团含糊的错误。
  • 实时比较。 编辑任一侧时 diff 都跟着更新,迭代 fixture 或响应很顺手。

实例演示#

示例,两个输入框分别填上一份小型配置文档修改前后的版本:

左侧

{
  "name": "ArpGate",
  "version": 1,
  "tags": ["json", "encoding"],
  "features": { "static": true, "backend": null }
}

右侧

{
  "name": "ArpGate",
  "version": 2,
  "tags": ["json", "encoding", "crypto"],
  "features": { "static": true, "backend": false, "offline": true }
}

diff 把变化逐条列出来:

changed  $.version           1 → 2
added    $.tags[2]           "crypto"
changed  $.features.backend  null → false
added    $.features.offline  true

注意什么没出现$.name(没变)、$.tags[0]$.tags[1](没变)、$.features.static(没变)。相等的分支不产出,所以哪怕两份文档各有好几个字段,四行 diff 就是全部故事。如果你再把两栏设成同一份文档,状态栏会切换成”无差异——两侧完全相同”。

常见问题#

为什么重排过顺序的数组会显示成全部改动?#

JSON 数组是有序的,相等性是按位置的。[1, 2][2, 1] 在下标 0 和下标 1 处都不同,所以 diff 会报两处改动。对顺序有意义的序列来说这是对的。如果你的数组其实代表一个集合,先在两份文档里排序(或归一化)再比,否则挪动会被看成编辑。

它能识别对象键被改名了吗?#

它会报成”一处删除 + 一处新增”,因为 JSON 没法表达”这个键变成了那个键”。把 enabled 改名成 active,会显示成 removed $.enabledadded $.active——两行,而不是一行”改名”。这才是数据变化的诚实表达。

类型变化长什么样?#

显示成单条 changed。一个值从字符串 "36" 变成数字 36,diff 会在该路径显示 "36" → 36——两侧序列化的差异把类型翻转暴露出来。nullfalse、数字变成对象,同理。

它能告诉我哪些字段没变吗?#

不能,这是故意的。把所有没变的字段也列出来,会在真实文档里把真正的改动淹没在噪声中。diff 只展示增量,相等的分支保持沉默。如果你要看某份文档的完整结构,用树形查看器。