json.stringify 不保证键序,但可通过预排序键或 replacer 参数实现稳定输出;sortedstringify 函数递归排序对象键,支持嵌套结构,但不处理循环引用等非 json 安全值;语义比对更推荐 lodash.isequal 等专用库。

JSON.stringify 本身不保证对象键的顺序,但可以通过预处理对象(如先对键排序再序列化)来实现稳定、可比对的字符串输出。
使用 replacer 参数控制键顺序
replacer 参数可以是数组或函数。用数组时,只保留并按指定顺序输出键;用函数时,可动态调整键值对。
- 数组方式:传入按字母序排列的键名数组,确保输出顺序一致
- 函数方式:在 replacer 函数中对 Object.keys(obj) 排序,再遍历返回值
通用排序序列化函数
封装一个稳定序列化函数,自动对所有层级对象的键做递归排序:
function sortedStringify(obj) {
if (obj === null || typeof obj !== 'object') return JSON.stringify(obj);
if (Array.isArray(obj)) {
return '[' + obj.map(sortedStringify).join(',') + ']';
}
const keys = Object.keys(obj).sort();
const pairs = keys.map(key =>
`"${key}":${sortedStringify(obj[key])}`
);
return `{${pairs.join(',')}}`;
}
这个函数能处理嵌套对象,且避免 JSON.stringify 默认的不可预测键序问题。
注意循环引用和特殊值
sortedStringify 不处理循环引用、undefined、函数、Symbol 等非 JSON 安全值。如需健壮比对,建议:
- 先用 JSON.stringify 的第二个参数(replacer)过滤掉不可序列化字段
- 对 Date、RegExp 等类型统一转为字符串表示(如 ISO 格式)
- 比对前确保两个对象结构等价,否则排序后仍可能因字段缺失导致差异
更推荐:用专门的 diff 库做语义比对
仅靠字符串比对有局限——比如 {a: 1, b: 2} 和 {b: 2, a: 1} 排序后相同,但若含 NaN、-0、+0 或不同数字精度(1 vs 1.0),JSON.stringify 输出可能不同,却语义相等。
- lodash.isEqual 或 fast-deep-equal 可做值语义比对,更可靠
- 需要可视化差异时,用 json-diff 或 deep-diff
- 仅当必须生成稳定哈希或存档快照时,才依赖排序后的 stringify
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











