JSON 差异对比
最后更新:2026年10月2日
比较两个 JSON 文档,只看到真正不同的地方。因为比较是结构化的,调整键的顺序或重新格式化不会产生任何差异;报告按路径列出每一处真实改动,全部在浏览器内完成。
结构化比较能看到什么
两个文档会先被解析,然后一起遍历。只有数据本身的差异会被报告:某一侧存在而另一侧没有的键、发生变化的某个值,或者类型发生变化的值——数字变成字符串,对象变成数组。空白和键的顺序完全不参与比较,因为解析之后它们已经不存在了。
类型变化只在发生的那个路径上报一次,而不会展开成下面每个叶子节点的一条删除加一条新增。当一个整棵子树改变了形状时,这让报告仍然可读。
为什么这不是文本行对比
文本差异——也就是 git diff 显示的那种——比较的是行。对 JSON 来说这常常会误导。当 JSON 由不同工具或不同版本的库生成时,重新缩进,或把同样的键按不同顺序输出,都是很正常的,而行对比会把它变成满屏改动,尽管数据完全相同。
下面两个文档是同一个文档。行对比会报告四行改动,而本工具不报告任何差异:
{"a": 1, "b": 2}
{
"b": 2,
"a": 1
}
反过来也成立,而这正是有用的地方:键名里改动一个字符,或某个数字从 3 变成 4,都只会显示为一处改动,而不会被格式化噪声淹没。
如何阅读路径表示法
每一处改动都会以路径的形式报告。$ 是文档根;点号进入对象键,方括号用于数组下标。所以 $.settings.indent 是 settings 里的 indent 键,$.features[2] 是 features 数组的第三项,而 $["weird key"] 表示一个不是简单标识符的键。这套写法与 JSON Pointer 风格一致,报告里的路径可以直接粘贴到其他 JSON 工具中使用。
差异对比无法告诉你什么
- 数组按位置匹配。在长数组开头插入一项,会把后面每个元素都往后推一位,于是它们都被报告为修改,尽管值只是移位了。这是任何没有可匹配键的差异工具的固有局限。如果数组元素带有稳定的
id,请先按它排序两侧,或比较按该 id 索引的版本。 - 它不是补丁。本工具报告差异,不输出 JSON Patch(RFC 6902)文档,也不检测移动的块。移动的值会表现为旧路径上的删除加上新路径上的新增。
- 值按精确比较。对解析器来说
1和1.0是同一个数,但1和"1"不同,而缺失的键与显式设为null的键也不同。
常见问题
键的顺序会影响比较结果吗?
不会。两个文档在比较前都会先被解析,对象的键按名字匹配而不是按位置。因此,重新格式化文档,或以不同顺序输出键,都会得到空的差异结果,这是正确的,因为数据本身没变。
为什么在数组开头插入一项会显示这么多差异?
数组是按位置匹配的,几乎所有结构化差异工具都如此。在长数组开头插入一项,会把后面每个元素的下标都往后推一位,于是它们都被报告为修改,尽管值只是移位了。没有可匹配的键,就无法知道哪些项是被插入而不是被改动。如果数组元素带有稳定的 id,请先按该 id 对两侧排序再比较。
如果有一侧不是有效的 JSON 会怎样?
比较会停止,并显示解析器自己的错误信息,同时标注是左侧还是右侧出错。两侧都能解析之前无法一起遍历,所以不会进行任何比较。
我的 JSON 会被上传吗?
不会。两个文档都在你的浏览器中用 JSON.parse 解析,并在内存中比较。没有任何请求携带它们,也没有账号或服务器端存储。你可以先加载页面再断开网络,比较依然可用。
它能判断某个值是被移动了还是被修改了吗?
不能。这个工具只报告差异,不生成补丁。它不会输出 JSON Patch 文档,也不会检测从一处移动到另一处的值;你会看到的是旧路径上的一条删除,加上新路径上的一条新增。
需要把 JSON 变成表格?JSON 转 CSV 可以做到。发现错误?联系我们。