JavaScript中的WeakMap和WeakSet是ES6引入的两种特殊数据结构,它们的核心特性和普通Map、Set不同,主要围绕弱引用设计,在内存管理和特定场景的数据关联上有独特作用。

WeakMap的基本特性与用法
WeakMap是一种键值对集合,它的键必须是对象,值可以是任意类型,且键对对象是弱引用关系,不会阻止垃圾回收。当WeakMap的键对象没有其他引用时,该键值对会被自动回收。
基本用法示例如下:
// 创建WeakMap实例
const weakMap = new WeakMap();
// 定义作为键的对象
const obj1 = { id: 1 };
const obj2 = { id: 2 };
// 设置键值对
weakMap.set(obj1, '关联数据1');
weakMap.set(obj2, '关联数据2');
// 获取值
console.log(weakMap.get(obj1)); // 输出:关联数据1
// 删除键值对
weakMap.delete(obj1);
console.log(weakMap.get(obj1)); // 输出:undefined
// 判断是否存在键
console.log(weakMap.has(obj2)); // 输出:trueWeakMap不支持遍历,也没有size属性,这是因为它的键值对可能随时被垃圾回收,无法保证遍历的准确性。
WeakSet的基本特性与用法
WeakSet是值的集合,它的成员必须是对象,且对成员对象是弱引用,同样不会阻止垃圾回收。当WeakSet的成员对象没有其他引用时,会被自动从集合中移除。
基本用法示例如下:
// 创建WeakSet实例
const weakSet = new WeakSet();
// 定义作为成员的对象
const item1 = { name: 'item1' };
const item2 = { name: 'item2' };
// 添加成员
weakSet.add(item1);
weakSet.add(item2);
// 判断是否存在成员
console.log(weakSet.has(item1)); // 输出:true
// 删除成员
weakSet.delete(item1);
console.log(weakSet.has(item1)); // 输出:false和WeakMap一样,WeakSet也不支持遍历,没有size属性,无法获取集合中的所有成员。
WeakMap和WeakSet的核心作用
1. 避免内存泄漏
普通Map和Set对键或成员是强引用,即使外部不再使用该对象,只要Map或Set还持有引用,对象就不会被垃圾回收,可能造成内存泄漏。而WeakMap和WeakSet的弱引用特性可以避免这个问题。
比如给DOM元素关联私有数据,使用普通Map时,即使DOM元素被移除,Map仍然持有引用,元素无法被回收:
const domMap = new Map();
const dom = document.getElementById('test');
domMap.set(dom, { clickCount: 0 });
// 后续移除dom元素
dom.remove();
// 此时domMap仍然持有dom的引用,dom无法被垃圾回收换成WeakMap后,当dom元素没有其他引用时,会被自动回收,对应的键值对也会消失:
const domWeakMap = new WeakMap();
const dom = document.getElementById('test');
domWeakMap.set(dom, { clickCount: 0 });
// 移除dom元素后,若没有其他引用,dom会被回收,WeakMap中的对应项也会自动清除
dom.remove();2. 存储对象的私有数据
WeakMap可以用来存储对象的私有属性,因为WeakMap的键是对象,外部无法直接遍历获取所有关联的私有数据,相对更安全。
示例如下:
const privateData = new WeakMap();
class User {
constructor(name) {
this.name = name;
// 存储私有数据,外部无法直接访问
privateData.set(this, { age: 0, salary: 0 });
}
setAge(age) {
const data = privateData.get(this);
data.age = age;
}
getAge() {
return privateData.get(this).age;
}
}
const user = new User('张三');
user.setAge(20);
console.log(user.getAge()); // 输出:20
// 外部无法直接获取privateData中存储的内容3. 标记对象状态
WeakSet可以用来标记对象是否处于某种状态,比如是否已经处理过、是否已经注册等,因为弱引用的特性,不会影响对象的生命周期。
示例如下:
const processedObjects = new WeakSet();
function processObject(obj) {
// 如果已经处理过,直接返回
if (processedObjects.has(obj)) {
return;
}
// 处理对象逻辑
console.log('处理对象', obj);
// 标记为已处理
processedObjects.add(obj);
}
const targetObj = { data: 'test' };
processObject(targetObj); // 输出:处理对象 { data: 'test' }
processObject(targetObj); // 无输出,因为已经处理过使用注意事项
- WeakMap的键、WeakSet的成员都必须是对象,不能是原始类型(如字符串、数字等)。
- 两者都不支持遍历、size属性、clear方法,无法批量操作所有键值对或成员。
- 只有在需要弱引用、避免内存泄漏的场景下才使用,普通数据关联场景用Map和Set更合适。
WeakMapWeakSetJavaScript弱引用内存管理修改时间:2026-06-03 00:30:10