人人都会AI编程

Map 与 Object 的对比与选型

更新时间:2026-07-11

在日常开发中,Object 是最常用的键值对集合,几乎所有的数据存储、配置对象、函数参数都用它。但随着 ES6 引入 Map,很多场景下 Map 是更优的选择。理解两者的差异,能让你在合适的场景选择合适的工具,避免性能隐患和潜在 bug。

两者核心差异一览

| 特性 | Object | Map |
|------|--------|-----|
| 键的类型 | 只能是字符串或 Symbol | 任意值(对象、函数、基本类型等) |
| 是否可迭代 | 默认不可迭代,需通过 Object.keys/values/entries 转换 | 直接可迭代,支持 for...of |
| 键的顺序 | 字符串键按添加顺序排列(ES2015 起),但存在历史遗留特例 | 严格按插入顺序排列 |
| 原型链干扰 | 存在原型链属性,可能意外继承如 toString 等键 | 无原型链干扰,完全纯净 |
| 大小获取 | 需用 Object.keys(obj).length | 直接使用 size 属性 |
| 性能 | 频繁增删键值对时较慢,适合静态数据 | 频繁增删场景性能更优 |
| 方法支持 | 无专用的增删改查方法 | 提供 set、get、has、delete、clear 等方法 |

键类型的灵活性

Object 的键实质上只能是字符串Symbol。即使你使用数字或布尔值作为键,也会被隐式转换为字符串:

const obj = {};
obj[1] = 'one';
obj[true] = 'true';
console.log(Object.keys(obj)); // ['1', 'true']  // 都变成了字符串

Map 则没有这个限制,键可以是任意数据类型,包括对象、函数、null 等,且不会发生类型转换:

const map = new Map();
const keyObj = { id: 1 };
map.set(keyObj, 'value for object');
map.set(1, 'one');
map.set(true, 'true');

console.log(map.get(keyObj)); // 'value for object'
console.log(map.get(1));      // 'one'
console.log(map.get(true));   // 'true'

这个特性让 Map 非常适合需要将对象作为键关联元数据的场景,比如缓存 DOM 节点对应的状态、存储对象之间的关系映射等。

迭代与遍历

Map 内置了迭代器,可以直接用 for...of 遍历,并且支持 forEach 方法,代码更简洁:

const map = new Map([['a', 1], ['b', 2]]);
for (const [key, value] of map) {
  console.log(key, value);
}
// 直接获取大小
console.log(map.size); // 2

Object 则需要先提取键、值或条目才能遍历,获取大小也需要额外计算:

const obj = { a: 1, b: 2 };
Object.entries(obj).forEach(([key, value]) => {
  console.log(key, value);
});
console.log(Object.keys(obj).length); // 2

原型链干扰陷阱

Object 继承了 Object.prototype,这意味着即使是空对象也会“存在”一些属性名,比如 toStringconstructor 等。使用对象作为哈希表时,如果不采取防御措施,就可能被这些属性干扰:

const obj = {};
console.log(obj.toString); // 函数,不是 undefined
console.log('toString' in obj); // true

如果接受外部输入作为键,就可能导致意外行为或安全风险。常见的防御措施是使用 Object.create(null) 创建无原型对象,而 Map 天然没有这个问题。

性能特点

  • 当需要频繁添加和删除键值对时,Map 的性能通常优于 Object。这是因为 Map 内部使用了更适合动态增删的数据结构。
  • 对于静态数据或者键明确为字符串的场景,Object 性能足够好,且配合对象字面量语法更简洁。
  • 在 V8 引擎中,Object 对属性访问有成熟的隐藏类优化,但如果频繁添加、删除属性,会破坏这种优化(对象进入字典模式),导致性能下降。

选型建议

优先使用 Object 的场景:

  • 键都是字符串或 Symbol,且结构固定(如数据模型、配置对象)。
  • 需要与 JSON 交互,因为 JSON 只支持字符串键,Map 无法直接序列化。
  • 使用对象字面量创建简单映射,代码更简洁易读。

推荐使用 Map 的场景:

  • 键不是字符串,例如需要将对象、函数等用作键。
  • 需要频繁增删键值对(如缓存、状态映射)。
  • 需要严格保持插入顺序且频繁迭代。
  • 键名有可能与原型链属性冲突,需要纯净的键集合。
// 示例:用 Map 存储 DOM 节点关联数据
const nodeMap = new Map();
const button = document.querySelector('button');
nodeMap.set(button, { clickCount: 0 });

// 示例:需要频繁增删的场景(如缓存)
const cache = new Map();
cache.set('user_1', userData);
cache.delete('user_1');

综合来说,没有绝对的“更好”,只有面对当前场景时的“更合适”。理解它们的差异,就能在项目中选择正确的工具,写出更健壮、更高效的代码。