JSON按键排序工具_递归按字母序排列对象键名与数组

把一段 JSON 里每个对象的键,按字母升序递归地重新排列,而数组元素的顺序保持不变。排序后结构更整齐,做 diff、比对两份配置或审阅接口返回时一眼就能看出差异。全部在你的浏览器本地完成,不会上传任何数据。

输入框支持 Ctrl / Cmd + Enter 排序,也可以一边输入一边看结果;下方「排序示例对照表」共 14 行,默认显示 12 行,点「加载更多」看余下 2 行;「复制对照表」复制制表符分隔文本。

使用方法

  1. 打开页面就有一组完整结果:输入框已经填入一份示例 JSON,结果区已经给出键排序后的格式化文本,不需要先填任何东西。
  2. 想排序自己的数据,就把输入框里的示例整段替换成你的 JSON;对象里的键会被递归排序,但数组里元素的先后不会动。
  3. 输入框按 Ctrl 或 Cmd 加回车会立即排序;也可以每敲一个字就实时看到结果。结果区第一行是排序后的 JSON 文本,可直接复制。
  4. 如果 JSON 写错了(少括号、多逗号、引号不配对),结果区会给出具体的解析错误,并点名出错原因,方便你定位。
  5. 结果区下面是「排序示例对照表」,列出 14 组输入与其排序后的首层键序,方便你核对排序规则是否理解正确。
  6. 本页不联网、不写本地存储,刷新即回到默认示例;你输入的 JSON 只在本机内存里算完即弃。

这个JSON按键排序工具能解决什么

这个JSON按键排序工具帮你把杂乱的 JSON 整理成键有序的形态。最常见的场景是比对两份结构相近的配置或接口返回:当键的顺序不一样时,文本 diff 会满屏飘红,而先统一排序再比对,差异就只剩真正的内容变动,一眼可见。

第二类场景是人工审阅。人眼读一段键乱放的对象很累,排过序后同类字段挨在一起,抽查某个字段在不在、值对不对都更快。对多层嵌套的配置尤为明显。

第三类场景是稳定输出。有些系统序列化 JSON 时键顺序不确定,做快照、做缓存键、做签名时顺序变了就会被认为「变了」。先按固定字母序排一遍,输出就稳定可复现。

必须写清的边界:本工具只排「对象的键」,不排数组元素、也不排对象里的标量值本身。也就是说,数组 [3,1,2] 排序后仍是 [3,1,2],字符串、数字、布尔也不会被改;它做的是结构整理,不是数据排序。

第四类场景是教学与排查。给新手演示 JSON 结构时,键排序后的对象更容易讲清楚层级关系;排查「为什么两份数据被认为不一致」时,先统一键序再比对,能快速排除「只是顺序不同」这类假差异,把注意力留给真正的值变化。它不依赖任何服务端与库,离线也能用,适合写进文档或脚本里反复调用。

递归排序与数组判定的原理

算法是递归的:遇到一个对象,先取它的全部键做字母升序排序,再按新顺序把每个键对应的值递归地再过一遍;遇到数组,则保持原顺序,只对其中的每一个元素递归处理;遇到字符串、数字、布尔、null 这类标量就原样返回。这样无论嵌套多深,每一层的对象键都会被排好。

关键点在于「怎么判断是不是数组」。普通 typeof [] 是 'object',和对象分不清;跨框架(不同 iframe、不同 realm)时 instanceof Array 还会失灵。所以本页用 Object.prototype.toString.call(v) === '[object Array]' 来判定,这条写法不受 realm 影响,是最稳的数组判据。

排序用的是 JavaScript 原生的字符串默认排序(按 UTF-16 码元升序),所以大写字母排在小写字母前面(Z 在 a 前)、数字按字符逐位排("10" 在 "2" 前)。下面这张变量表列出了本页用到的判定量与取值含义。

关于排序的稳定性还有一点值得说明:原生 sort 对键名做字符串比较,而同一层的对象键在 JSON 里天然唯一,不会出现重复键,因此不会因为「相同键名」引发顺序抖动;也正因键唯一,递归重排不会产生键覆盖,每一层输出的键集合与输入完全一致,只是顺序变了。你可以用它做可复现的输出,而不必担心排着排着丢了某个字段。

变量含义取值影响
input原始 JSON 文本任意合法 JSON排序的唯一输入
v遍历中的值对象 / 数组 / 标量决定走排序还是原样返回
isArr数组判定toString.call(v)==='[object Array]'为真才保留元素顺序
keys排序后的键字母升序的键名列表决定对象输出顺序

完整示例

默认示例是 {"name":"Bob","age":30,"tags":["b","a"],"meta":{"z":1,"a":2}}。首层四个键 name、age、tags、meta 排序后变成 age、meta、name、tags;其中 meta 是个对象,它的键 z、a 也被排成 a、z;而 tags 是数组 ["b","a"],顺序原样保留。结果区里那一整段就是:

{
  "age": 30,
  "meta": {
    "a": 2,
    "z": 1
  },
  "name": "Bob",
  "tags": [
    "b",
    "a"
  ]
}

把输入换成 {"b":1,"a":2},输出就是 {"a":1,"b":2};换成 {"name":"x","age":1,"z":9},首层键排序后是 age、name、z。两个结果都是当场算出来的,不是写死的。

需要特别留意的是 meta 内部的 a、z 排序与首层无关:它们是 meta 这一层的键,所以只在这一层内按字母排,不会因为首层已经有了 age、name、tags 就被拉平到顶层。递归的边界正是这样一层一层各自独立、互不串扰——你甚至可以嵌套十几层,每一层都只管自己这一层的键顺序,不会向上或向下泄漏。理解了这一点,就能放心把它用在任意深度的真实报文上。

排序示例对照表

下表共 14 行:覆盖单层、多层、含数组、含大小写、含数字键等典型输入。每行的「排序后首层键序」都由页面里的同一套递归函数现场算出,和你在上方输入框里得到的结果用的是同一套逻辑;默认显示 12 行,点「加载更多」看余下 2 行。

示例输入排序后首层键序
{"b":1,"a":2}a, b
{"name":"x","age":1,"z":9}age, name, z
{"x":1,"y":2,"z":3,"a":4}a, x, y, z
{"c":{},"a":{},"b":{}}a, b, c
{"keep":[3,1,2],"order":[9,8]}keep, order
{"Z":1,"a":2}Z, a
{"age":30,"meta":{"z":1,"a":2}}age, meta
{"1":1,"10":2,"2":3}1, 10, 2
{"_":1,"a":2}_, a
{"a":[1,2],"b":{"y":1,"x":2}}a, b
{"A":2,"a":1}A, a
{"data":{"nested":{"c":1,"b":2,"a":3}}}data
{"b":1,"a":[5,3,4]}a, b
{"z":1,"y":2,"x":3,"w":4}w, x, y, z

横向读这张表能得出两条实用结论:第一,数组顺序永远不动(keep、order 那一行,以及任何带数组的例子),因为只有对象的键才被排序;第二,排序是字符串序而非数字序,"1"、"10"、"2" 排出来是 1、10、2,大写 Z 也排在小写 a 前面。

结果边界与错误提示

常见问题

为什么我的数组被排了序?

如果你看到数组顺序变了,几乎一定是把数组误写成了对象,或者本想排对象却贴了一段别的内容。本工具的数组判定用 Object.prototype.toString.call,标准写法下的数组会严格保持原顺序,只有对象的键才会被排序。

大写字母为什么排在小写前面?

因为排序按字符的 UTF-16 码元比较,大写字母(如 Z,码元 90)小于小写字母(如 a,码元 97)。这是 JavaScript 的默认字符串排序行为,数字字符同理按字符逐位比,所以 "10" 会排到 "2" 前面。

数字键的排序符合直觉吗?

不符合数值直觉,但符合字符串直觉。"1"、"10"、"2" 按字符逐位比较会得到 1、10、2,因为 "1" 与 "10" 首位都是 "1","10" 的第二位 "0" 小于 "2" 的首位 "2"。若想按数值排,需要先把键转成数字再排,本工具不做这步。

跨 iframe 的数组会被判错吗?

不会。本页用 Object.prototype.toString.call(v) === '[object Array]' 判定数组,这条写法不受 realm 影响;相比之下用 instanceof Array 在跨 iframe 时才可能失灵,所以这里特意避开了它。

嵌套多少层都没问题吗?

递归对普通业务 JSON 完全够用。只有极深(成千上万层)的嵌套才可能触及调用栈上限,正常配置与接口返回远达不到,本页没有为这种极端情况做专门兜底。

排序后值会变吗?

不会。排序只重新排列「对象的键」,字符串、数字、布尔、null 这些标量原样保留,数组元素顺序也保留。它做的是结构整理,不是数据重排,所以你可以用它来稳定输出而不改变语义。

我的 JSON 会被上传吗?

不会。整个排序过程都跑在你的浏览器本地,文本只存在于本机内存,页面既不发请求也不写本地存储,刷新后输入框回到默认示例。

为什么对照表用 TSV 复制而不是 CSV?

对照表是展示性的小表,用制表符分隔文本复制最轻量,粘进表格软件会自动分列;它不是 CSV 文件导出场景,所以不需要 BOM 与引号转义那一套。

相关工具