map 使用 samevaluezero 算法判断键相等,故 nan 自等、+0 与 -0 等价;无法用 === 或 object.is 预判,需通过 map/ set 行为间接验证;对象字面量、0 与 false、字符串 "nan" 等均不满足该算法。

Map 键名对 NaN 和 -0 的判定,不依赖 ===,而是按 ECMAScript 规范定义的 SameValueZero 算法执行。识别这类键是否“命中”,关键在于理解该算法的两个特殊规则:NaN 自等、+0 与 -0 等价。
NaN 作为键时的识别方法
尽管 NaN === NaN 为 false,但 Map 内部会将所有 NaN 视为同一键。因此:
- 只要用
NaN调用set(),后续任何位置再用NaN调用get()、has()或delete(),都会作用于同一个条目 - 不能靠
===或Object.is()预判——必须实际操作 Map 才能验证行为 - 示例:
const m = new Map(); m.set(NaN, 'x'); m.get(NaN)返回'x';而m.get(Number('foo'))同样返回'x'(因为Number('foo') === NaN)
-0 与 +0 混用时的判定表现
-0 和 +0 在 SameValueZero 下完全等价,Map 不区分二者:
-
m.set(-0, 'a'); m.get(+0)→ 返回'a' -
m.set(+0, 'b'); m.get(-0)→ 返回'b' - 插入顺序不影响逻辑结果,但会影响遍历时第一个被保留的零值的符号(如
Array.from(m.keys())[0] === -0可能为true,取决于引擎实现) - 注意:
JSON.stringify(-0)和String(-0)都输出"0",不能用于键唯一性预处理
如何验证某个值是否与已有键“SameValueZero 相等”
没有直接暴露 SameValueZero 的全局函数,但可借助 Map 或 Set 的行为间接判断:
- 构造一个临时
new Map([[key, 1]]),再用待测值get()——若返回1,说明它与keySameValueZero 相等 - 或用
new Set([key, candidate]),检查.size === 1;成立即表示二者被判定为相同值 - 特别注意:字符串
"NaN"、数字NaN、undefined、null互不相等,类型不同就一定不满足 SameValueZero
常见误判场景提醒
这些情况容易让人以为“键匹配了”,实则不符合 SameValueZero:
- 用对象字面量
{}当键:每次新建都是新引用,new Map().set({}, 1).has({})为false - 把
0和false当作等价键:它们类型不同(number vs boolean),SameValueZero 不认为相等 - 依赖
toString()或valueOf()做键归一化:Map 不调用这些方法,只做原始值或引用比较










