WeakMap 是键必须为对象且弱引用的集合,支持自动垃圾回收,适合存储组件私有状态以避免内存泄漏;相比 Map 和闭包,它天然对齐实例生命周期,常用于类组件状态管理或函数组件中与 DOM 关联的临时数据。

WeakMap 是 JavaScript 中一种特殊的键值对集合,它的键必须是对象,且对键的引用是“弱引用”——也就是说,当该对象没有其他强引用存在时,它会被垃圾回收器自动清理,WeakMap 中对应的条目也会随之消失。这个特性让它非常适合用来存储组件的私有、临时状态,尤其是避免内存泄漏。
为什么用 WeakMap 而不是普通 Map 或闭包?
普通 Map 会强持有 key(即使是对象),阻止其被回收;闭包虽然能封装状态,但在类组件或函数组件多次渲染/重建时,容易因闭包捕获旧引用导致状态错乱或内存堆积。WeakMap 的 key 是对象实例本身(如 DOM 元素、class 实例、React 组件实例等),天然与生命周期对齐:组件卸载 → 实例被销毁 → WeakMap 条目自动消失。
在类组件中用 WeakMap 存储私有状态
适合需要为每个组件实例单独维护一份不可枚举、不可外部访问的状态(比如缓存计算结果、暂存事件监听器引用、防抖定时器 ID 等)。
// 创建一个模块级 WeakMap,用于存储各实例的状态
const componentState = new WeakMap();
class MyComponent {
constructor() {
// 每个实例首次访问时初始化自己的状态对象
componentState.set(this, {
isLoading: false,
cache: new Map(),
debounceTimer: null
});
}
get state() {
return componentState.get(this);
}
startLoading() {
this.state.isLoading = true;
}
cleanup() {
if (this.state.debounceTimer) {
clearTimeout(this.state.debounceTimer);
}
}
}
在函数组件中配合 useRef + WeakMap 管理 DOM 关联状态
React 函数组件没有 this,但可以将 DOM 元素或自定义对象作为 WeakMap 的 key。常见于封装自定义 Hook,为特定 DOM 节点绑定临时状态(如拖拽坐标、焦点历史、动画帧 ID)。
立即学习“Java免费学习笔记(深入)”;
// 示例:为某个 input 元素缓存上次输入值(不依赖 React state)
const inputCache = new WeakMap();
function useInputLastValue(inputRef) {
useEffect(() => {
const el = inputRef.current;
if (!el) return;
// 初始化该元素的状态
if (!inputCache.has(el)) {
inputCache.set(el, { lastValue: '' });
}
const handleInput = () => {
const cache = inputCache.get(el);
cache.lastValue = el.value;
};
el.addEventListener('input', handleInput);
return () => el.removeEventListener('input', handleInput);
}, [inputRef]);
return () => {
const el = inputRef.current;
return el && inputCache.get(el)?.lastValue;
};
}
// 使用:
function MyForm() {
const inputRef = useRef();
const getLast = useInputLastValue(inputRef);
return (
);
}
注意事项和边界情况
- WeakMap 的 key 只能是对象(不能是字符串、数字、null),所以不能用字符串 ID 当 key 来模拟“命名空间”
- 无法遍历 WeakMap(没有 keys()、values()、entries() 方法),调试时看不到内容 —— 这既是隐私保障,也是限制,需靠设计规避调试困难
- 不要试图用 WeakMap 替代 React state 做视图响应式更新;它只管存储,触发重渲染仍需 useState/useReducer
- 在 SSR 环境中,WeakMap 仍可工作,但服务端渲染后对象不会复用,客户端 hydration 时会新建实例,因此 WeakMap 内容自然隔离,无需手动清理


















