WeakSet
=======

**`WeakSet`** — это набор значений, поддерживающих сборку мусора, включая объекты и незарегистрированные символы. Каждое значение в `WeakSet` может встречаться только один раз, оно уникально в коллекции `WeakSet`.

Описание
--------

Значения в WeakSet должны поддерживать сборку мусора. Большинство примитивных типов данных могут не иметь времени жизни, поэтому они не могут быть сохранены. Объекты и незарегистрированные символы могут быть сохранены потому что они поддерживают сборку мусора.

Ключевые отличия от `Set`:

* `WeakSet` — это набор только **объектов и символов**. В отличие от `Set` он не может содержать произвольные значения любого типа.
* `WeakSet` является *слабым* в том смысле, что ссылки на объекты в `WeakSet` хранятся *слабо*. Если нет других ссылок на значение, хранящееся в `WeakSet`, эти значения могут быть удалены сборщиком мусора.

**Примечание:** Это также означает, что нет списка текущих значений сохранённых в наборе. Объекты `WeakSet` не перечислимы.
### Вариант использования: обнаружение циклических ссылок

Функциям, которые вызывают себя рекурсивно, необходим способ защиты от циклических структур данных путём отслеживания того, какие объекты уже были обработаны.

Объекты `WeakSet` идеально подходят для этого:


```js
// Выполняем `fn` для всего, что хранится внутри объекта.
function execRecursively(fn, subject, _refs = new WeakSet()) {
  // Избегаем бесконечно рекурсии
  if (_refs.has(subject)) {
    return;
  }

  fn(subject);
  if (typeof subject === "object" && subject) {
    _refs.add(subject);
    for (const key in subject) {
      execRecursively(fn, subject[key], _refs);
    }
    _refs.delete(subject);
  }
}

const foo = {
  foo: "Foo",
  bar: {
    bar: "Bar",
  },
};

foo.bar.baz = foo; // Циклическая ссылка!
execRecursively((obj) => console.log(obj), foo);
```


Здесь `WeakSet` создаётся при первом запуске и передаётся вместе с каждым последующим вызовом функции (с использованием внутреннего параметра `_refs`).

Количество объектов или порядок их обхода не имеют значения, поэтому использование `WeakSet` более эффективно, чем `Set` для отслеживания ссылок на объекты, особенно если задействовано очень большое количество объектов.

Конструктор
-----------

`WeakSet()` (en-US)

Создаёт новый объект `WeakSet`.

Свойств экземпляра
------------------

Эти свойства определены в `WeakSet.prototype` и есть у всех экземпляров `WeakSet`.

`WeakSet.prototype.constructor`

Функция-конструктор, создающая экземпляр объекта. Для экземпляров `WeakSet` начальным значением является конструктор `WeakSet` (en-US).

`WeakSet.prototype[@@toStringTag]`

Начальным значением свойства `@@toStringTag` является строка `"WeakSet"`. Это свойство используется в `Object.prototype.toString()`.

Методы экземпляра
-----------------

`WeakSet.prototype.add()`

Добавляет `value` в объект `WeakSet`.

`WeakSet.prototype.delete()`

Удаляет `value` из `WeakSet`. После этого `WeakSet.prototype.has(value)` будет возвращать `false`.

`WeakSet.prototype.has()`

Возвращает булево значение, показывающее присутствует ли `value` в объекте `WeakSet` или нет.

Примеры
-------

### Использование `WeakSet`


```js
const ws = new WeakSet();
const foo = {};
const bar = {};

ws.add(foo);
ws.add(bar);

ws.has(foo); // true
ws.has(bar); // true

ws.delete(foo); // удаляем foo из набора
ws.has(foo); // false, foo был удалён
ws.has(bar); // true, bar сохранился
```


Обратите внимание, что `foo !== bar`. Хотя это похожие объекты, *это не **один и тот же объект***. И поэтому они оба добавляются в набор.

Спецификации
------------

| Specification |
| --- |
| ECMAScript Language Specification # sec-weakset-objects |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Полифил `WeakSet` в `core-js`
* `Map` (en-US)
* `Set`
* `WeakMap`