一文搞懂 Map、Set、WeakMap、WeakSet

一文搞懂 Map、Set、WeakMap、WeakSet

面试常问,但很多人只会用 Map 和 Set,Weak 这两个一问就懵。今天一次讲清。


一、先看一句话区别

  • Map:键值对集合,键可以是任意类型
  • Set:值的集合,值不重复
  • WeakMap:键只能是对象,弱引用,不可遍历
  • WeakSet:值只能是对象,弱引用,不可遍历

二、Map vs 普通对象

普通对象:

js

ini 复制代码
const obj = {};
obj['name'] = '张三'; // 键只能是字符串/Symbol

Map:

js

c 复制代码
const map = new Map();
map.set('name', '张三');
map.set(123, '数字键');
map.set({}, '对象键'); // 键可以是任意类型

Map 的优势

  • 键可以是任意类型
  • 有 .size
  • 可遍历
  • 频繁增删性能好

常用方法

js

arduino 复制代码
const map = new Map();

map.set('a', 1);      // 增
map.get('a');         // 查 → 1
map.has('a');         // 判断 → true
map.delete('a');      // 删
map.size;             // 大小
map.clear();          // 清空

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

三、Set:不重复的集合

js

vbscript 复制代码
const set = new Set([1, 2, 3, 3, 3]);
console.log(set); // Set { 1, 2, 3 }

常用方法

js

arduino 复制代码
set.add(1);       // 增
set.has(1);       // 判断
set.delete(1);    // 删
set.size;         // 大小

经典用途:数组去重

js

ini 复制代码
const arr = [1, 2, 2, 3, 3, 3];
const unique = [...new Set(arr)]; // [1, 2, 3]

四、WeakMap:弱引用的键值对

js

vbnet 复制代码
const wm = new WeakMap();
const key = {};

wm.set(key, '一些数据');
wm.get(key); // '一些数据'

限制

  • 键只能是对象
  • 不可遍历 (没有 keys、forEach)
  • 没有 .size
  • 键是弱引用

弱引用是什么意思?

js

ini 复制代码
let key = { name: '张三' };
const wm = new WeakMap();
wm.set(key, '数据');

key = null; // 断开引用
// 因为 wm 是弱引用,这个对象可以被垃圾回收

对比普通 Map:

js

ini 复制代码
let key = { name: '张三' };
const map = new Map();
map.set(key, '数据');

key = null;
// map 里还留着这个对象,不会被回收 → 内存泄漏

WeakMap 的意义:对象没别的地方用了,自动回收。


五、WeakSet:弱引用的集合

js

ini 复制代码
const ws = new WeakSet();
const obj = {};

ws.add(obj);
ws.has(obj);   // true
ws.delete(obj);

ws.size;        // undefined
ws.forEach(...) // ❌ 没有

和 WeakMap 一样,只是它是值的集合,不是键值对。


六、核心对比表

特性 Map Set WeakMap WeakSet
存什么 键值对 值 键值对 值
键/值类型 任意 任意 只能是对象 只能是对象
可遍历 ✅ ✅ ❌ ❌
有 size ✅ ✅ ❌ ❌
引用方式 强引用 强引用 弱引用 弱引用
GC 自动回收 ❌ ❌ ✅ ✅

七、WeakMap 的实际用途

1. 给对象存私有数据

js

kotlin 复制代码
const privateData = new WeakMap();

class Person {
  constructor(name) {
    privateData.set(this, { name });
  }

  getName() {
    return privateData.get(this).name;
  }
}

p 被回收时,privateData 里的数据也自动消失。

2. DOM 元素关联数据

js

javascript 复制代码
const cache = new WeakMap();

function attachData(element, data) {
  cache.set(element, data);
}

// element 被移除后,关联数据自动回收

用 Map 的话,DOM 元素删了,数据还留着 → 内存泄漏。

3. 缓存

js

csharp 复制代码
const cache = new WeakMap();

function process(obj) {
  if (cache.has(obj)) return cache.get(obj);
  const result = /* 复杂计算 */;
  cache.set(obj, result);
  return result;
}

对象不用了,缓存自动清掉。


八、为什么 WeakMap 不可遍历?

因为弱引用的对象随时可能被 GC 回收。

如果允许遍历,结果会不稳定------你遍历时,对象可能已经被回收了。

所以规范直接禁止遍历。


九、怎么选?

需求 用哪个
需要键值对,键任意类型 Map
去重、快速判断存在 Set
给对象关联数据,不想阻止回收 WeakMap
给对象打标记,不想阻止回收 WeakSet

十、一句话总结

  • Map / Set:可遍历、有大小、强引用
  • WeakMap / WeakSet:不可遍历、无大小、弱引用

Weak 的核心就是"不阻止垃圾回收",专门用来给对象挂数据、做缓存、打标记。


附:记忆口诀

Map 存键值,Set 存值。

Weak 只能存对象,不阻止 GC,还不能遍历。


如果这篇文章帮你理清了这四个的区别,点个赞让更多人看到。

有疑问欢迎评论区交流,一起进步。

相关推荐
三十而立洋1 小时前
前端模块化的演进:从全局变量到 Import Maps
前端·javascript·前端工程化
用户1733598075371 小时前
纯前端 PDF 按书签拆分避坑指南:拆分后章节对不上?
前端·javascript·vue.js
AI情绪识别开源1 小时前
检信 ALLEMOTION AI驱动振动感知健康分析平台核心基础
javascript
мо仙堡杠把子ご灬1 小时前
Flex 自适应布局:告别 calc,用一个 height-auto 搞定
前端·javascript
程序员阿黄1 小时前
月圆人圆:中秋佳节传统文化站(月夜主题重设计版)项目全解析
javascript·html5·毕设
OpsEye1 小时前
开源 AI 网关自研 vs 商用,企业该怎么权衡取舍
javascript·ai编程
ShineWinsu2 小时前
对于HTML:HTML常见标签的解析—下
前端·css·面试·html·标签·表单·emmet
怕浪猫2 小时前
给AI配一台电脑,开源版Muse来了,OpenMuse赶紧去二次开发吧
javascript·面试·github
Jack N3 小时前
【Strapi 系列之二】Collection / Single / Component 怎么选?Strapi 字段大全一篇讲透
前端·javascript·strapi