可靠的深度相等断言需语义感知:递归比对、识别NaN/-0、跳过循环引用、忽略键序;推荐用Cypress/Vitest/Jest/Chai内置方法,避免JSON.stringify;专业diff选jsondiffpatch或deep-diff;手写须用Object.is、类型判断、WeakMap防循环。

直接用 === 或 JSON.stringify() 断言对象相等,基本都会出错。真正可靠的深度相等断言,得靠语义感知的比对逻辑——它要能递归进每一层、识别 NaN 和 -0 的区别、跳过循环引用、忽略键顺序,失败时还要告诉你具体哪一字段不一致。
用测试框架内置的深度断言最稳妥
主流测试工具都已内置成熟实现,无需自己造轮子:
-
Cypress:直接写
expect(actual).to.deep.equal(expected),自动处理嵌套对象、数组、null、NaN;Date 类型建议提前转成字符串或时间戳再比 -
Jest / Vitest:用
expect(actual).toEqual(expected),默认支持 Map/Set/undefined/循环引用;Date 推荐统一调用.toISOString(),RegExp 用.toString()标准化 -
Chai:选
expect(a).to.deep.equal(b)(Expect 风格)或a.should.deep.equal(b)(Should 风格),语义清晰,错误提示友好
别踩字符串化比较的坑
JSON.stringify(a) === JSON.stringify(b) 看似简单,但有硬伤:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 属性顺序不同就判为不等(
{a:1,b:2}≠{b:2,a:1}) - 丢掉
undefined字段、无法序列化function和Symbol -
NaN变成null,-0和+0被视为相同 - 遇到循环引用直接抛
TypeError
需要结构化差异报告时用专业 diff 库
当不只是“通过/失败”,还要定位变更点、生成对比日志或对接 JSON Patch 流程:
立即学习“Java免费学习笔记(深入)”;
-
jsondiffpatch:调用
diff(oldObj, newObj)返回标准 delta 对象,支持压缩、逆向 patch,适合灰度对比或后端同步 - deep-diff:轻量级,返回扁平化的变更列表(标记 N/D/E/A),带路径和操作类型,方便做 UI 高亮或日志归档
- 二者都正确处理数组内容变化(如
["a","b"] → ["a","c"]只标索引 1,不整个数组报错)
手写深度比较函数的关键细节
若必须自研(如离线环境或性能极致场景),以下三点绕不开:
- 用
Object.is()替代===:确保Object.is(NaN, NaN) === true,且Object.is(-0, +0) === false - 先区分类型:用
Array.isArray()判数组,再用typeof和instanceof处理 Date、RegExp、Map、Set - 防循环引用:用
WeakMap缓存已比对过的引用对,避免递归栈溢出

















