【JS】WeakMap和Map、弱引用和强引用

10 阅读1分钟

前期提要

const map = new Map();
let obj = { name: "A" };

map.set(obj, "value");
obj = null;

你以为:
“我已经 obj = null 啦,应该没人引用 { name: "A" } 啊,为什么还不能回收呢?”


🧠 真相:Map 自身会“记住”你的对象!

当你执行:

map.set(obj, "value");

发生了什么?

  1. map 存储了一个 内部引用(强引用) 指向 { name: "A" }
  2. 即使你外部 obj = nullmap 里面仍然引用着它。
  3. 所以在 JS 引擎看来,这个对象还“活着” —— 它依然是“可达”的。

🧬 “可达性” 是垃圾回收的核心依据

JavaScript 的垃圾回收机制不看你“写没写 null”,它只看对象是否还有引用指向它:

  • 如果有任何活着的地方引用它(强引用) ,那它就不会被 GC 回收。
  • Map 是一个活着的对象,它自己持有 obj 的引用

所以:

map.set(obj, "value");  // obj 在 Map 中“活着”
obj = null;             // 外部不再引用,但 Map 还在
// --> obj 对应的对象仍然不能回收

对比:Map vs WeakMap

操作MapWeakMap
set(obj, val)创建一个强引用 → obj 永远活着创建一个弱引用 → obj 可被 GC
obj = nullMap 仍保留对象 → 不可回收没有引用了 → GC 会自动清掉条目

举个更直观的例子:

let obj = { name: "A" };
const map = new Map();
map.set(obj, "value");

obj = null; // 你以为断开了,但实际上...

Map 里相当于内部还保留着这个:

map = {
  [[object Object]]: "value"
}

{ name: "A" } 仍然“藏”在 map 的键里,无法被回收。


✅ 总结

  • Map 是普通对象容器,所有键都是强引用,会阻止 GC。
  • 即使你外部 obj = null,Map 本身还引用着那个对象,它就还活着
  • 如果你想让这个引用是“可丢弃”的(可被 GC 回收),就应该用 WeakMap