最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何利用Object.is应对NaN===NaN为false引发的数值去重失效
时间:2026-07-19 17:09:54 编辑:袖梨 来源:一聚教程网
Object.is 能正确识别 NaN 相等,因其采用 SameValue 算法,使 Object.is(NaN, NaN) 为 true,且区分 +0 和 -0;它不进行类型转换,比 === 更严格,适用于精确值比较场景。
Object.is 为什么能正确识别 NaN 相等
NaN === NaN 返回 false,这是 JavaScript 的语言规范决定的——任何值与 NaN 用严格相等比较都为 false。这导致用 Set 或 Array.prototype.filter 去重时,NaN 被当作不同值反复保留。
Object.is 是唯一把 NaN 当作“自身相等”的内置方法:Object.is(NaN, NaN) 返回 true,且它还修复了 0 和 -0 的误判问题(+0 === -0 为 true,但 Object.is(+0, -0) 为 false)。
注意:Object.is 不是类型转换工具,它比 === 更严格,也更语义准确——它定义的是“SameValue 零值相等算法”,专为精确值比较而生。
用 Object.is 实现数组数值去重(含 NaN)
直接用 Set 无法处理 NaN,因为 Set 内部用的是 SameValueZero 算法(和 === 行为一致),不是 SameValue。必须手动实现去重逻辑:
常见做法是遍历 + Object.is 判重:
function uniqueByObjectIs(arr) { const seen = []; return arr.filter(item => { const notExists = !seen.some(seenItem => Object.is(seenItem, item)); if (notExists) seen.push(item); return notExists; });}<p>// 示例uniqueByObjectIs([1, NaN, 2, NaN, 0, -0]); // [1, NaN, 2, 0, -0]
要点:
-
seen.some(...)必须用Object.is,不能用===或== -
0和-0会被视为不同项,符合预期(若业务需要合并,得额外判断) - 性能上是 O(n²),大数据量时慎用;如需优化,可配合
Map存储已见值的字符串化键(但要注意NaN序列化后都是"NaN",反而会把多个NaN合并——所以仍需自定义键生成逻辑)
替代方案:Map + 自定义 key 生成函数
如果数组很大,又必须支持 NaN、+0/-0 精确区分,可以借助 Map 实现 O(n) 去重,关键是设计能区分这些值的键:
一个稳妥的 key 生成方式:
function getUniqueKey(val) { if (Number.isNaN(val)) return 'NaN@' + Math.random().toString(36).slice(2, 8); if (val === 0 && 1 / val === -Infinity) return '−0'; return String(val);}
但这个方案有缺陷:每次调用 getUniqueKey(NaN) 生成不同 key,破坏一致性。真正可靠的写法是用 Object.is 手动维护键集合,或接受 NaN 在 Map 中只能存一个(因 Map 的 has 方法仍基于 SameValueZero)。所以——
- 多数场景下,老实用
filter + some + Object.is更清晰可靠 - 不要试图用
JSON.stringify或String()作为去重 key,它们对NaN、undefined、function等都失效 -
Map本身不解决NaN键重复问题,它的set和has仍遵循 SameValueZero
在 reduce 或 Set 扩展中误用 Object.is 的典型错误
有人会写:[...new Set(arr.map(x => Object.is(x, x) ? x : x))],这毫无意义——Object.is(x, x) 永远为 true,没改变原始值。
另一个常见错误是混用比较目标:
// ❌ 错误:拿 Object.is 去比较索引和值arr.filter((v, i) => Object.is(v, i))<p>// ✅ 正确:只用于值与值之间比较arr.filter((v, i) => !seen.some(s => Object.is(s, v)))
还有人试图覆盖 Array.prototype.includes 的行为,但该方法内部固定使用 SameValueZero,无法被 Object.is 替代——必须手写逻辑。
最易被忽略的一点:Object.is 是浅比较,对对象或数组仍然无能为力;如果你的“数值”其实是包装对象(如 new Number(NaN)),Object.is 也会返回 false,因为它比的是引用而非包装值。
相关文章
- 苹果折叠屏爆料汇总:售价超两万,比例阔折叠 07-30
- 纪念碑谷3 纪念碑谷3手游玩法详解与体验评测 07-30
- 晴空双子金卡阵容推荐 晴空双子高性价比氪金养成指南 07-30
- 大周列国志全新派系系统 07-30
- 兔小萌世界甜系小房间搭建指南 兔小萌世界高颜值甜系房间布置全流程详解 07-30
- 大周列国志全新剧本包西汉剧本包 07-30