Map 是允许任意类型值(包括对象、函数等)作为键的集合类型,解决普通对象键仅限字符串/Symbol且会强制类型转换的问题;它按插入顺序遍历,提供 O(1) 增删查性能,但不支持 JSON 序列化和原型链查找。

Map 是什么?它不是 Object 的替代品,而是专门解决键类型限制的集合类型
JavaScript 的 Map 是一个内置的键值对集合,核心设计目标是允许**任意类型值作为键**(包括 Object、Function、Symbol 甚至 null 和 undefined),而普通对象的键只能是字符串或 Symbol(且会自动转为字符串)。这意味着你不能用一个对象实例作为普通对象的键来安全存取数据,但 Map 可以。
key 类型差异导致的实际问题:为什么用 {} 存对象作 key 会失效?
当你写 const obj = {}; obj[{a:1}] = 'value',实际执行的是 {a:1}.toString() → '[object Object]',所有对象键都会被强制转成相同字符串,造成覆盖。而 Map 用 SameValueZero 算法比较键,能区分不同对象实例。
const map = new Map();
const key1 = { id: 1 };
const key2 = { id: 1 };
map.set(key1, 'first');
map.set(key2, 'second');
console.log(map.size); // 2 —— 两个不同对象,都被独立保存
console.log(map.get(key1)); // 'first'
console.log(map.get(key2)); // 'second'
对比普通对象:
const obj = {};
obj[{id:1}] = 'first';
obj[{id:1}] = 'second';
console.log(Object.keys(obj)); // ['[object Object]'] —— 只剩一个键
console.log(obj['[object Object]']); // 'second' —— 后者覆盖前者
遍历与顺序:Map 保证插入顺序,Object 的键序在 ES2015+ 虽有规范但仍有陷阱
Map 的迭代器(keys()、values()、entries())严格按插入顺序返回;而普通对象的 for...in 或 Object.keys() 虽在现代引擎中大多保持插入顺序,但对数字字符串键(如 '10'、'2')仍会按数值大小排序,且早期行为不一致,不可靠。
立即学习“Java免费学习笔记(深入)”;
-
Map中map.set('2', 'a').set('10', 'b')→keys()返回['2', '10'] - 普通对象
{'2': 'a', '10': 'b'}→Object.keys()在多数环境返回['2', '10'],但{'10': 'b', '2': 'a'}仍可能被重排 - 更危险的是:对象中混入数字键(
obj[10] = 'b'; obj[2] = 'a')→Object.keys(obj)必定返回['2', '10'](升序)
性能与 API 设计:Map 更适合高频增删查,Object 更适合静态配置或原型继承场景
Map 的 size 属性是 O(1),has/get/set/delete 均为平均 O(1);而对象要获取键数量得用 Object.keys(obj).length(O(n)),且没有原生的 hasKey 方法(得靠 hasOwnProperty 或 in,后者还查原型链)。
但注意:Map 无法被 JSON 序列化(JSON.stringify(new Map()) → '{}'),也不参与原型链查找——它就是纯数据容器。如果你需要默认方法(如 toString)、可枚举属性或与 class 实例自然融合,对象仍是更自然的选择。
容易忽略的一点:Map 的键比较是基于引用(SameValueZero),所以用字面量对象反复作为键查不到值——map.get({x:1}) 永远是 undefined,除非你复用同一个对象引用。











