WeakMap 是实现 JavaScript 私有数据的理想工具,因其键为弱引用对象且不暴露键列表,可防内存泄漏并保障封装性;通过以实例为键、私有状态为值,实现类的私有字段隔离。

WeakMap 是 JavaScript 中实现真正私有数据的理想工具,它能避免内存泄漏,同时让外部代码无法直接访问内部状态。
为什么 WeakMap 适合存私有变量
WeakMap 的键必须是对象,且对键的引用是“弱引用”——当该对象不再被其他地方引用时,即使它还在 WeakMap 中作为键,垃圾回收器也能正常回收它。这天然规避了因缓存导致的内存泄漏问题。更重要的是,WeakMap 实例本身不暴露键列表(没有 keys()、values() 或 entries() 方法),外部无法遍历或探测其中存储了哪些对象,从而保证了封装性。
用 WeakMap 模拟类的私有字段
在类中,把实例对象作为 WeakMap 的键,把私有数据(如对象)作为值。每个实例对应一份独立的私有状态,且外部无法通过实例访问到这些数据。
示例:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
立即学习“Java免费学习笔记(深入)”;
const privateData = new WeakMap();
class Counter {
constructor(initial = 0) {
// 将当前实例作为键,存入私有状态
privateData.set(this, { count: initial });
}
increment() {
const data = privateData.get(this);
data.count++;
}
getCount() {
return privateData.get(this).count;
}
}
const c1 = new Counter(5);
const c2 = new Counter(10);
console.log(c1.getCount()); // 5
console.log(c2.getCount()); // 10
// privateData 无法被外部读取或枚举,c1 和 c2 的私有状态完全隔离
配合闭包进一步增强封装(可选进阶)
如果希望连 WeakMap 实例本身也不暴露在模块顶层,可用立即执行函数包裹,让 WeakMap 变成真正的模块级私有变量。
示例:
立即学习“Java免费学习笔记(深入)”;
const createCounter = (function() {
const privateData = new WeakMap(); // 外部完全不可见
return class Counter {
constructor(initial = 0) {
privateData.set(this, { count: initial });
}
increment() { privateData.get(this).count++; }
getCount() { return privateData.get(this).count; }
};
})();
// 使用方式不变,但 privateData 不再是全局可访问变量
注意事项和常见误区
- WeakMap 的键只能是对象(包括函数、数组、DOM 元素等),不能是原始值(如字符串、数字、symbol)
- 不能用 for...of 或 forEach 遍历 WeakMap;也没有 size 属性,无法得知它存了多少项
- 不要试图用 WeakMap 替代 Map 做通用缓存——它不支持非对象键,也不适合长期持有数据
- 私有数据仍可通过反射手段(如调试器、performance.memory 等)间接观察,但常规 JS 代码无法访问,已满足工程级封装需求

















