JavaScript WeakSet
外观
WeakSet 是 JavaScript 中 ES6 引入的一种特殊集合类型,用于存储弱引用的对象。与普通的 Set 不同,WeakSet 中的对象不会被垃圾回收机制(Garbage Collection)阻止回收,这使得它在某些特定场景下非常有用。本文将详细介绍 WeakSet 的特性、用法以及实际应用场景。
简介[编辑 | 编辑源代码]
WeakSet 是一种集合数据结构,但只能存储对象引用,并且这些引用是“弱引用”(Weak References)。这意味着:
- 如果 WeakSet 中的对象没有其他强引用指向它,垃圾回收器会自动将其从 WeakSet 中移除。
- WeakSet 不可迭代,也没有 `size` 属性或 `clear()` 方法。
WeakSet 的主要用途是存储临时或辅助的对象,而无需担心内存泄漏问题。
基本语法[编辑 | 编辑源代码]
WeakSet 的构造函数可以接受一个可迭代对象(通常是数组)作为参数,初始化时会将数组中的对象添加到 WeakSet 中。
const weakSet = new WeakSet();
const obj1 = {};
const obj2 = {};
// 添加对象
weakSet.add(obj1);
weakSet.add(obj2);
// 检查对象是否存在
console.log(weakSet.has(obj1)); // 输出: true
// 删除对象
weakSet.delete(obj1);
console.log(weakSet.has(obj1)); // 输出: false
与 Set 的区别[编辑 | 编辑源代码]
WeakSet 和普通 Set 的主要区别如下:
特性 | WeakSet | Set |
---|---|---|
存储类型 | 仅对象 | 任意值 |
可迭代 | 否 | 是 |
垃圾回收 | 弱引用,不影响回收 | 强引用,阻止回收 |
`size` 属性 | 无 | 有 |
`clear()` 方法 | 无 | 有 |
实际应用场景[编辑 | 编辑源代码]
WeakSet 通常用于以下场景:
1. 避免内存泄漏[编辑 | 编辑源代码]
在需要临时存储对象但又不希望阻止垃圾回收时,WeakSet 非常有用。例如,在事件监听器中存储回调对象:
const trackedObjects = new WeakSet();
function trackObject(obj) {
trackedObjects.add(obj);
}
const button = document.querySelector('button');
trackObject(button);
// 如果 button 被移除 DOM,垃圾回收器会自动清理
2. 标记对象[编辑 | 编辑源代码]
WeakSet 可以用于标记某些对象是否经过特定处理:
const processedItems = new WeakSet();
function processItem(item) {
if (processedItems.has(item)) {
console.log('Item already processed');
return;
}
processedItems.add(item);
console.log('Processing item...');
}
const item1 = { id: 1 };
processItem(item1); // 输出: Processing item...
processItem(item1); // 输出: Item already processed
限制[编辑 | 编辑源代码]
WeakSet 有以下限制:
- 不能存储原始值(如数字、字符串、布尔值等)。
- 无法遍历或获取其大小。
- 没有 `forEach` 或类似方法。
总结[编辑 | 编辑源代码]
WeakSet 是一种特殊的集合类型,适用于存储对象的弱引用,避免内存泄漏。它不适合需要遍历或查询大小的场景,但在标记对象或临时存储时非常高效。
进阶示例[编辑 | 编辑源代码]
以下是一个更复杂的示例,展示如何结合 WeakSet 和 WeakMap 实现私有属性:
const privateData = new WeakMap();
const initializedObjects = new WeakSet();
class MyClass {
constructor() {
privateData.set(this, { secret: Math.random() });
initializedObjects.add(this);
}
getSecret() {
if (!initializedObjects.has(this)) {
throw new Error('Object not initialized');
}
return privateData.get(this).secret;
}
}
const instance = new MyClass();
console.log(instance.getSecret()); // 输出随机数