Map能直接用任意值作键,因其底层用哈希表实现、键比较用SameValueZero算法、键以原始形态独立存储、无原型干扰且按插入顺序迭代;Object键只能是String或Symbol,依赖隐式字符串化,易致冲突和类型丢失。

因为 Map 是专为键值对存储设计的原生数据结构,底层采用哈希表实现,且键比较使用 SameValueZero 算法(类似 ===,但 NaN === NaN 为 true),不依赖字符串化,所以能直接用任意值作键。
Object 的键受限于属性名语义
JavaScript 中对象本质是属性集合,而属性名在语言规范中被定义为 String 或 Symbol。当你写 obj[{}],引擎会立刻调用 {}.toString() 得到 "[object Object]",再作为字符串键存入——这不是“支持对象作键”,只是隐式转换。
这种机制带来两个问题:
- 多个不同对象可能转成相同字符串(如
{a:1}和{b:2}都变成"[object Object]"),造成键冲突 -
null、undefined、数字0、NaN等原始值也会被强制转为字符串,失去原本的区分能力
Map 的键是独立存储的引用或值
Map 内部维护一个键值对列表(实际是哈希桶数组),每个键以原始形态保存:
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
- 对象键存的是内存引用地址,两个不同对象即使内容相同,也被视为不同键
- 函数键同理,
function a(){}和function b(){}是两个独立键 - 原始值如
NaN、0、-0、null、undefined全部保留本体,用 SameValueZero 判断相等(例如map.set(NaN, 'x'); map.get(NaN)能正确返回'x')
没有原型链和默认属性干扰
Object 继承自 Object.prototype,自带 toString、hasOwnProperty 等属性,容易发生意外覆盖或遍历污染;而 Map 是纯净容器,map.keys() 只返回你显式 set 过的键,不混入任何内置属性。
这也意味着你可以安全地用 DOM 元素、React 组件实例、类实例甚至另一个 Map 作为键,不会触发副作用或类型转换。
插入顺序与可预测行为
Map 明确保证键值对按插入顺序迭代,这背后依赖其内部链表或有序数组结构。而 Object 的属性顺序在 ES2015 后虽有约定(数字键先、字符串键后、Symbol 最后),但仍是“枚举顺序”而非“插入顺序”,且受引擎优化影响不稳定。Map 的任意键类型支持,和它的顺序保障、无隐式转换、无原型干扰,是一体设计的结果,不是单独添加的功能补丁。










