跳转到内容

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()); // 输出随机数

参见[编辑 | 编辑源代码]

模板:JavaScript Modern Features