Map和Set是什么_与对象和数组有何区别【教程】

13次阅读

map和Set是为高频查找、去重、映射设计的原生结构,非对象/数组替代品;Map键支持任意类型且保序,Set去重时间复杂度O(1),优于数组O(n²)。

Map和Set是什么_与对象和数组有何区别【教程】

Map 和 Set 是专门做查找的键值/唯一值容器

它们不是对象或数组的替代品,而是为高频查找、去重、映射关系设计的原生数据结构。用错场景(比如只存几个静态配置就硬套 Map)反而增加开销;该用却不用(比如频繁 includes 数组查重),性能会掉得明显。

为什么不能直接用对象代替 Map?

对象的 key 只能是字符串symbol,而 Map 的 key 可以是任意类型——函数、对象、NULL、甚至另一个 Map。更关键的是:对象不保证插入顺序(尤其在旧引擎或非字面量创建时),而 Map 遍历一定按插入顺序返回。

  • 错误写法:const obj = {}; obj[{}] = 'a'; → 实际 key 被转成 "[Object Object]",多个空对象都撞成同一个 key
  • 正确写法:const map = new Map(); map.set({}, 'a'); → 每个对象都是独立 key
  • 额外代价:对象要手动维护 sizeMap 直接有 map.size

Set 去重比数组 Filter + indexOf 快得多

Set 底层是哈希实现,add/has 平均时间复杂度是 O(1);而数组去重常用 arr.filter((v, i) => arr.indexOf(v) === i),每次 indexOf 都要遍历,整体是 O(n²)。

  • 简单去重:[...new Set(arr)] —— 清晰、快、一行解决
  • 但注意:Set 只对原始值(String/number/Boolean)和同一引用对象判等;[1,2] === [1,2] 是 false,所以两个相同数组放进 Set 仍是两个元素
  • 如果要深去重数组或对象,Set 不适用,得自己序列化或用库

别把 Map/Set 当万能筐,小心内存和可读性陷阱

它们没有数组的索引访问(map[0] 无效),也不支持 map.foreach 以外的高阶方法(如 map.mapfilter)。想链式处理,得先转成数组(Array.from(map.values())),这会触发一次遍历+内存分配。

  • 误用场景:只存 3 个配置项,却用 new Map([['host', 'a'], ['port', 80], ['ssl', true]]) —— 对象更轻、可读性更好
  • 真需要动态增删 + 快速查 key 时才上 Map;只要去重或存在性判断,优先 Set
  • node.js 早期版本(Map 的序列化(jsON.stringify)会丢失数据,必须手动展开;现在虽已支持,但跨环境传输仍建议转 plain object

最常被忽略的一点:Map 和 Set 的迭代器不可复用。调用一次 map.keys() 得到的迭代器,遍历完就耗尽了,再 for...of 就什么也不吐——不是 bug,是设计如此。需要多次遍历时,得重新调用方法或缓存为数组。

text=ZqhQzanResources