json.stringify 不适合直接比较表单对象是否相等,因其无法正确处理属性顺序、undefined、函数、date、regexp 等,且浏览器遍历顺序不一致;仅可在严格标准化(剥离非序列化字段、类型归一、键排序)后用于轻量浅层比对。

直接用 JSON.stringify 比较表单对象是否相等,看似简单,但极易出错——因为对象属性顺序、undefined 值、函数、Date、RegExp 等都无法被 JSON 正确序列化,且不同浏览器/环境对属性遍历顺序的处理也不完全一致。所以“用 JSON.stringify 对比差异”本身不是可靠方案,但可以借助它在**可控前提下做轻量级浅层比对**,前提是先做好数据标准化。
确保只比对可序列化的纯数据字段
表单数据常含 DOM 元素、事件监听器、方法等,这些必须提前剥离。建议从表单提取时就只保留键值对(如用 new FormData() 转为 plain object,或手动 Object.fromEntries(new FormData(form))):
- 过滤掉
undefined、null、函数、Symbol、Date、RegExp 等非 JSON 安全类型(JSON.stringify会静默忽略它们) - 统一转换数值型字符串为数字(如
"123"→123),避免"123"和123被误判为不同 - 空字符串
""和null/undefined是否等价,需按业务约定提前归一化(例如都转成null)
用标准化后的对象生成稳定 JSON 字符串
即使属性顺序不同,JSON.stringify 默认仍可能产出不同结果。解决办法是:传入排序后的 key 数组作为 replacer 参数,强制统一序列化顺序:
function stableStringify(obj) {
if (obj === null || typeof obj !== 'object') return JSON.stringify(obj);
const keys = Object.keys(obj).sort();
return JSON.stringify(obj, keys, 2);
}
这样 {b: 1, a: 2} 和 {a: 2, b: 1} 都会生成相同字符串。
对比前先深克隆原始对象再处理
为不破坏原对象,所有清洗、归一化操作都应在副本上进行:
- 用
structuredClone(obj)(现代浏览器支持)或JSON.parse(JSON.stringify(obj))(仅适用于纯数据)创建副本 - 对副本调用归一化函数(如去除空格、转类型、过滤无效字段),再用
stableStringify序列化 - 两个表单分别走同样流程,最后比对两个字符串是否完全相等
真正需要“差异详情”时,别依赖 stringify
如果不仅要判断“是否不同”,还要知道“哪里不同”(比如哪个字段变了、旧值新值是什么),JSON.stringify 无法提供结构化差异。此时应改用专门的 diff 工具:
- 轻量级:用 jsondiffpatch,输入两个对象,输出带路径和变更类型的 patch
- 零依赖:手写递归比对函数,逐层检查 key 是否存在、值是否相等(注意处理 NaN、-0、+0 等边界)
- 表单场景优化:只比对已定义的字段名列表(白名单),跳过动态生成或无关字段
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











