Map 与 WeakMap 怎么选?弱引用是否代表一定不会泄漏?
先理解原理和示例,再练习完整口述与追问。
回答要点
Map 可遍历、有 size;WeakMap 不可枚举,键弱引用;垃圾回收时机不可控;闭包和其他强引用仍可能保活;注意运行时版本。
原理拆解
Map 可以使用各种类型的键,支持遍历、size 和明确删除,适合需要统计、LRU 或主动管理生命周期的缓存。WeakMap 常用于给对象附加私有元数据;只有 WeakMap 持有键时,不会仅因这条弱引用就阻止键被垃圾回收。由于回收时机不可观察且不可预测,WeakMap 不提供遍历和 size,也不适合依赖“某时刻所有条目一定清理完成”的业务。
面试中常说 WeakMap 只能用对象作键,这对许多旧运行时成立。现代规范还允许非注册 Symbol 作键,但旧浏览器或本项目 Node 16.19 不应默认拥有该能力;跨这些环境的代码使用对象键,并先核实目标环境。Symbol.for 返回的注册 Symbol 不属于可用的弱键。
WeakMap 也不是防泄漏开关。如果组件仍被全局数组、事件监听器、未清理的定时器或闭包强引用,对象就不会因为另一个容器是 WeakMap 而消失。排查时要看实际引用链,先清理不需要的监听、订阅、任务和缓存。WeakRef、FinalizationRegistry 也不能用于必须按时释放的资源或关键业务流程。
参考:MDN WeakMap。
示例与推演
DOM 元素作为键保存统计数据:Map 若长期存在,就会强引用已经移出页面的元素;WeakMap 可以避免仅由缓存键保活它。但如果另一个 window 事件闭包仍引用该元素,它仍不能回收。LRU 需要 size、遍历与明确淘汰,则更适合 Map。
易错点
不能写一个稳定测试要求“100ms 后弱键必定被回收”。弱引用释放时机不适合承担文件关闭、支付或会话失效等确定性业务。
参考回答可直接练习口述
Map 可以使用各种类型的键,支持遍历、size 和明确删除,适合需要统计、LRU 或主动管理生命周期的缓存。WeakMap 常用于给对象附加私有元数据;只有 WeakMap 持有键时,不会仅因这条弱引用就阻止键被垃圾回收。由于回收时机不可观察且不可预测,WeakMap 不提供遍历和 size,也不适合依赖“某时刻所有条目一定清理完成”的业务。