← 返回题目列表

Map 和 Set 有什么特点?和 Object、Array 有什么区别?

高频 中等 第 14 / 28 题 更新于 2026/07/27
ES6MapSet数据结构

简化版

Map 是键值对集合,键可以是任意类型;Set 是不重复值集合。相比 Object,Map 更适合频繁增删查和任意键;相比 Array,Set 更适合去重和快速判断存在。

详细版

Map 示例:

const map = new Map();
map.set({ id: 1 }, 'user');
map.get(key);
map.has(key);

Set 示例:

const set = new Set([1, 2, 2]);
console.log([...set]); // [1, 2]

Object 的 key 主要是字符串或 Symbol,Map 的 key 可以是对象、函数、NaN 等。Set 判断重复使用 SameValueZero,NaN 会被认为等于 NaN

完整版教学

一、Map 解决 Object 做字典的痛点

用 Object 做字典时,key 会转成字符串:

const obj = {};
obj[{ a: 1 }] = 'x';

对象 key 会变成 "[object Object]",容易冲突。Map 可以直接用对象作为 key,引用不同就是不同 key。

二、Map 的遍历顺序

Map 会按插入顺序遍历:

for (const [key, value] of map) {
  console.log(key, value);
}

它还有明确的 size 属性,比 Object 统计 key 数量更方便。

三、Set 的典型用途

数组去重:

const unique = [...new Set(list)];

快速存在性判断:

const selected = new Set(ids);
selected.has(id);

当数据量较大时,Set.prototype.has 通常比数组 includes 更适合高频查找。

四、WeakMap 和 WeakSet 简要区别

现代 ECMAScript 中,WeakMap 的 key 可以是对象或非全局注册的 Symbol,且是弱持有,不会仅因作为键就阻止垃圾回收。工程中最常见的键仍是对象,适合存对象私有元数据、DOM 关联数据。它不可遍历,也没有 size,代码不能观察键何时被回收。

五、面试追问与工程落地

Map/Set 常被追问“对象作为 key 时怎么比较”。Map 使用引用身份比较对象 key。两个长得一样的对象字面量不是同一个引用,所以会被当成不同 key。这个点在缓存、节点映射、权限集合里很重要。

还可能问 Set 去重对象是否有效。new Set([{id:1}, {id:1}]) 不会按 id 去重,因为两个对象引用不同。对象数组去重要用 Map 按业务 id 建索引,或者手动维护 key。

工程里 Map 不一定总比 Object 好。普通 JSON 数据、接口参数、简单记录结构用 Object 更直观;需要任意类型 key、频繁增删、保持插入顺序、明确 size 时再优先 Map。

六、从相等规则与生命周期选择集合

MapSet 判断键或成员时使用 SameValueZero 语义。它与 === 大体一致,但 NaN 会被视为等于自身,+0-0 也视为同一个值;对象仍按引用身份比较,内容相同的两个对象是两个键。

const set = new Set([NaN, NaN, +0, -0])
console.log(set.size) // 2
const map = new Map()
map.set({ id: 1 }, 'A')
console.log(map.get({ id: 1 })) // undefined,不是同一引用
需求合适结构核心原因
任意类型键、需要遍历Map键类型不受字符串限制
唯一值集合Set内建去重和成员判断
给对象附加元数据且不阻止回收WeakMap键是弱持有且不可枚举
JSON 传输的普通记录Object序列化和字段语义直观

规范只要求这些集合在平均情况下提供次线性访问时间,并没有承诺每次操作都严格是 O(1)。现代 ECMAScript 的弱集合可弱持有对象或非全局注册的 Symbol;工程兼容性答题中最常见、最稳妥的 WeakMap 键仍是对象。

WeakMap 不能枚举、没有 size,正是为了避免通过 API 观察垃圾回收时机;不能把它当作“会自动清空的 Map”来调试业务数据。

七、常见误区与追问

  • 误区:Map 的键最终都会转成字符串。 Map 保留键的类型与身份,数字 1 和字符串 "1" 是两个键。
  • 误区:Set 能按对象内容自动去重。 对象按引用比较,两个结构相同但引用不同的对象会同时保留。
  • 误区:WeakMap 的键回收时间可以预测。 垃圾回收时机不可观察也不受业务代码保证。
  • 追问:Set 为什么能去掉多个 NaN? SameValueZero 把 NaNNaN 判断为相同成员。
  • 追问:Map 一定比 Object 快吗? 不一定,性能取决于数据规模、操作模式和引擎;应先按键语义、遍历和序列化需求选择。
  • 追问:WeakMap 为什么不能遍历? 若能枚举键,程序就可能观察某个对象何时被回收,带来不确定行为。
  • 追问:Map 如何转换为可 JSON 序列化的数据? 可按协议转成条目数组 Array.from(map);键若不是 JSON 可表达类型,还需自行编码。

八、加强记忆

Map 记“任意 key 的字典”,Set 记“不重复值的集合”。Object 更像普通记录结构,Array 更像有序列表;需要频繁查存在和去重时优先想 Set。

选择集合前先问键的类型、是否要枚举以及是否应影响键的生命周期,比只背 API 更可靠。