1. WeakMap 是什么?
WeakMap 内部结构:
[ {弱引用: 键对象} -> {值} ]
当“键对象”被回收,WeakMap 自动删除该条目。
生活中类比
想象你在咖啡厅有个「储物柜」,每个储物柜对应一个顾客的「包包」。
- 你想存包包里的东西(比如钥匙、手机)放到柜子里,柜子是根据包包来识别的。
- 重要的是:如果顾客拿走了包包(包包不见了),你也不想一直占着柜子,这个柜子能自动清理空柜子。
在代码中
- WeakMap 的键只能是对象(这里就是包包),值可以是任何数据(包包里的东西)。
- 当这个键(对象)没有别的引用了(顾客离开了,包包不见了),垃圾回收机制会自动清理 WeakMap 里对应的条目。
- 你不能遍历 WeakMap(因为这些键随时可能被清理,遍历会不稳定)。
用途举例:
- 存储某个 DOM 元素相关的数据,当元素被删除时,相关数据也自动被清理。
- 存储某个对象的私有信息,不暴露到外面,且不会阻止这个对象被销毁。
2. WeakRef 是什么?
生活中类比
你想看某位朋友,但不想硬拉着他(不给他压力)。
你留了一个「电话薄」上的号码(弱引用),想打电话给他:
- 如果朋友还在,你能打电话找到他。
- 但如果朋友已经搬走了(被垃圾回收了),你拿电话也联系不上了。
在代码中
WeakRef是一个对象的弱引用。- 你不能直接保证这个对象一定还在,用
.deref()尝试拿对象,可能拿到,也可能拿不到(对象被回收了)。 - 适合缓存或者监听那些“存在即使用,消失则无所谓”的对象。
用途举例:
- 缓存一些大对象,比如图片、模型,允许内存紧张时回收。
- 观察者模式里存弱引用,避免订阅者对象一直被占用。
📝 总结对比
| 方面 | WeakMap | WeakRef |
|---|---|---|
| 键类型 | 只能是对象 | 持有一个对象的弱引用 |
| 作用 | 关联对象与数据,不阻止对象回收 | 弱引用某对象,允许回收,需手动取值 |
| 是否可遍历 | 不可 | 不是容器,不可遍历 |
| 典型用途 | 存储对象的私有数据或状态 | 缓存对象、观察者、资源管理 |
你可以把:
WeakMap想成「根据对象自动管理私有数据的柜子」;WeakRef想成「能随时失效的轻薄引用,拿不拿到对象由 GC 决定」。
⚠️WeakMap和WeakRef主要是为了解决什么问题?
WeakMap 和 WeakRef 主要是为了解决 内存泄漏 和 内存管理效率问题,帮助程序更智能地管理对象生命周期,避免无用数据长期占用内存。
WeakMap 主要解决的问题
1. 对象相关数据的自动垃圾回收
传统的 Map 用对象做键时,只要 Map 里有引用,这些对象就不会被回收。
可能导致内存泄漏:即使对象不再使用了,但相关数据依然占用内存。
WeakMap 的键是弱引用,当键对象不再被其他地方引用,垃圾回收机制会自动清除对应的数据。
举例:你给 DOM 元素存一些数据,如果元素被删除了,相关数据自动被清理,避免内存泄漏。
WeakRef 主要解决的问题
2. 缓存和资源管理中的“软引用”
有些缓存不想强制保留对象(避免内存占用过大),又想有机会访问。
传统的缓存(Map + 对象引用)会一直保留对象,导致内存占用。
WeakRef 允许对对象持有“弱引用”,不阻止垃圾回收。
对象不被强引用时可能被回收,缓存变“软”,系统内存紧张时能自动释放。
举例:图片、模型等大资源缓存,用 WeakRef 保存,内存紧张时自动释放。
总结
| 问题 | 传统方案的痛点 | WeakMap / WeakRef 解决方案 |
|---|---|---|
| 对象关联数据的内存泄漏 | Map 持有强引用,导致对象无法释放 | WeakMap 通过弱引用键自动清理 |
| 缓存资源占用过多内存 | 强引用缓存导致内存占用 | WeakRef 允许缓存对象被回收,节省内存 |
啥是WeakMap和Map?啥是弱引用、强引用?,请看➡️ 点击链接