一文搞懂 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,还不能遍历。


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

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

相关推荐
幸运小猿26 分钟前
模拟慢上传-处理超时重试image 丢失线上问题
前端·javascript·html
利威尔xu1 小时前
Go IM 源码实战(13):30 个会话只有 2 个红点,未读数错在三条路径
redis·后端·微服务·面试·golang
速易达网络3 小时前
ECharts 图表制作完全指南:从零到可视化实战
前端·javascript·echarts
paopaokaka_luck4 小时前
灾害应急物资管理系统(AI应急助手、Echarts可视化数据看板、捐赠入库联动、 物资全流程管理、库存变动追溯、灾情资讯与互动反馈、物资发放公示)
java·前端·javascript·spring boot·mysql·tomcat·echarts
kyriewen4 小时前
我验了 7 种 sticky 失效说法:3 种根本不成立
前端·javascript·程序员
我命由我123455 小时前
Python 实用操作 - 文件操作(打开与关闭文件、读取文件、文件写入)
java·开发语言·前端·javascript·数据库·python·java-ee
Momo__6 小时前
你写的 import 重试,从来没生效过
前端·javascript·typescript
IT规划师6 小时前
面试中被嘲笑Token放在redis里,该如何应对?
redis·面试
1M556 小时前
AI应用后端工程(03):回答输出一半就断了:AI 流式接口如何定义成功与失败?
python·面试·职场和发展·计算机专业·agent开发