Map键等价性由Object.is()判定:基本类型按值比较(NaN===NaN为true),对象按引用比较({}!=={}),+0与-0在Map中被兼容视为相等。

因为 Map 的键名比较使用的是 Object.is() 语义,而 Object.is({},{}) 返回 false —— 两个空对象是不同引用,不满足等价条件。
Map 键等价性的底层规则
ES6 中 Map 不用 ===,也不把键转成字符串,而是调用 Object.is() 判断两个键是否“等价”。该方法对基本类型和引用类型有明确区分:
- 基本类型(数字、字符串、布尔、undefined、null、Symbol、BigInt):按值比较,
Object.is(5, 5)→ true,Object.is(5, "5")→ false - NaN 特殊处理:
Object.is(NaN, NaN)→ true(这是唯一与===不同的地方) - 对象(包括数组、函数、日期等):只看内存地址(引用),
Object.is({}, {})→ false,哪怕内容完全一样 - +0 和 -0 被视为不等:
Object.is(+0, -0)→ false(但 Map 内部对 +0/-0 做了额外兼容,实际中map.get(-0)能取到map.set(+0, 'x')存的值)
为什么 {} 与 {} 是两个独立键?
每次写 {} 都创建一个新对象,分配新的内存地址。Map 在存取时用 Object.is 比较键,而两个不同对象的引用永远不相等:
-
const m = new Map(); m.set({}, 'a'); m.set({}, 'b');→ Map 中实际有 两个键,长度为 2 -
m.get({})总是 undefined,因为你每次传入的都是全新对象,和之前存进去的任何一个都不等价 - 想复用同一个键,必须复用**同一个引用**:
const key = {}; m.set(key, 'a'); m.get(key);→ 才能拿到 'a'
常见误区与替代方案
开发者常误以为“结构相同就等价”,但 Map 不做深比较。若需按内容识别对象键,可考虑:
- 用 JSON.stringify(obj) 作为字符串键(仅适用于简单、可序列化的对象)
- 用 WeakMap 存储对象实例级元数据(键必须是对象,且不阻止 GC)
- 手动维护对象 ID 或 symbol 属性,再用该属性作 Map 键
- 对复杂场景,改用库如
fast-deep-equal+ 自定义缓存逻辑,而非依赖 Map 原生行为
Map 的设计目标是快速、确定、无歧义的键查找,不是智能匹配。理解 Object.is 的行为,就能预判几乎所有键等价性问题。










