WeakMap 的键是弱引用,不会阻止垃圾回收,因此无法通过浅拷贝对象作为键来“持有”原对象;其正确用法是以原始对象为键、拷贝对象为值,用于深拷贝中防循环引用。

WeakMap 的键本身就是弱引用,不会阻止垃圾回收——所以“浅拷贝对象作为 WeakMap 的键名导致的持有”这个前提不成立。你无法用浅拷贝后的对象去“持有”原对象,因为 WeakMap 不会因键存在而延长其生命周期。
WeakMap 的键不构成强引用
WeakMap 的设计目标之一就是避免内存泄漏。它的键必须是对象,且对键的引用是「弱引用」:只要该对象在其他地方不再被任何强引用持有,即使它还作为 WeakMap 的键存在,垃圾回收器也会照常回收它。
- 你把一个对象 a 放进 WeakMap 作键,之后把 a 置为
null或离开作用域 → 它会被回收,WeakMap 中对应条目自动失效 - 你对 a 做浅拷贝得到 b,再把 b 当作 WeakMap 的键 → 这和 a 完全无关,b 是独立对象,有自己的生命周期
- WeakMap 不会、也不能通过键反向“持有”或“追踪”原始对象
容易混淆的典型场景:深拷贝中用 WeakMap 缓存已处理对象
真正用到 WeakMap 的地方,是在手写深拷贝函数时解决循环引用问题。此时 WeakMap 用原始对象作键、拷贝后对象作值,目的是避免重复拷贝和无限递归:
- 不是“把浅拷贝结果当键”,而是“把原始引用对象当键”
- WeakMap 在这里起缓存作用,且不干扰原始对象的回收时机
- 如果误把浅拷贝后的对象(比如
Object.assign({}, obj)的结果)当作键存入 WeakMap,那它只是个普通新对象,跟原对象无关联,也起不到缓存或防循环的作用
如果你实际遇到了“对象没被回收”,问题不在 WeakMap 键上
常见真实原因包括:
- 该对象仍被闭包、全局变量、事件监听器、定时器、DOM 引用等强引用持有着
- 你用的是 Map 而非 WeakMap(Map 会强持有键,导致内存泄漏)
- 你把基本类型(如字符串、数字)误当对象传给 WeakMap.set(),会直接报错,根本存不进去
- 你依赖了 WeakMap 的条目“一直存在”,但其实它可能随时消失——WeakMap 不支持遍历、没有 size,也不保证条目存活时长
WeakMap 本身不会导致持有问题。它解决的恰恰是持有问题。关键在于:用对对象(原始引用)、用对时机(缓存/元数据场景)、别和 Map 混用。










