Map 明显优于普通对象,因其键类型多样、增删高效、遍历有序、size 获取直接且无原型干扰。

在频繁增删键值对的场景下,Map 明显优于普通对象,关键不在于“快一点”,而在于“稳、准、可预期”。普通对象在动态修改中容易隐性退化,Map 则始终维持高效结构。
看键类型是否多样
如果键可能是对象、函数、数组、NaN 或 Symbol,必须选 Map。普通对象会把所有非字符串键转成字符串,导致冲突:
- {[1,2]: 'a', [1,2]: 'b'} 实际只剩一个 "1,2" 键;
- new Map().set([1,2], 'a').set([1,2], 'b') 能存两个独立项,因数组引用不同。
看操作频率与数据量
当单个对象/Map 的增删次数超过几百次,或总键数常达千级及以上,性能差异就明显显现:
- 普通对象频繁 delete 可能触发 V8 “字典模式”,后续所有属性访问从 O(1) 降为 O(n);
- Map 的 set() 和 delete() 始终是哈希表操作,平均 O(1),百万级测试中通常快 2–3 倍;
- map.clear() 是 O(1),而清空对象需遍历 keys 或重赋 {}(后者还可能断开原型链)。
看遍历与 size 获取是否频繁
需要反复迭代或查总数时,Map 更轻量、更直接:
- map.size 是属性读取,O(1);Object.keys(obj).length 需构建新数组,O(n);
- for (const [k, v] of map) 直接迭代,无中间数组;for (const k of Object.keys(obj)) 多一次内存分配;
- Map 迭代严格按插入顺序,数字键不会被提前排序;对象遍历顺序混合数字升序 + 字符串插入序,逻辑难预测。
看是否需避免原型干扰
普通对象继承 toString、hasOwnProperty 等方法,若业务中用这些字符串作键,会覆盖原型行为:
- obj.toString = 'custom' → 破坏对象自身方法;
- Map 不挂载任何默认键,map.get('toString') 总是返回 undefined(除非你主动设),安全无副作用。


















