Привет, Хабр!
Когда дело доходит до коллекций данных в JavaScript, большинство разработчиков сразу вспоминают про массивы, объекты, Map или Set. Но есть и другие, менее известные структуры данных, которые можно назвать «инструментами для особых случаев» — это WeakMap и WeakSet. 
WeakMap и WeakSet — это структуры, которые созданы для работы с объектами. Их основная фичи — слабые ссылки, благодаря которым можно избежать утечек памяти. Эти структуры подчищают за собой автоматически, когда объект, используемый в них, становится недостижимым.
Однако их область применения не ограничивается только управлением памятью. WeakMap и WeakSet позволяют:
- Хранить данные, которые исчезают сами, без явного удаления. 
- Создавать скрытые хранилища для приватных данных, не изменяя сам объект. 
- Автоматическое удаление временных данных, связанных с объектами, например, кэшей. 
WeakMap
WeakMap — это коллекция пар ключ‑значение, где:
- Ключами могут быть только объекты. 
- Значениями могут быть любые данные, от строк до функций. 
- Ключи имеют слабую ссылку, что позволяет сборщику мусора удалять их, если они больше нигде не используются. 
Основное отличие от обычного Map в том, что WeakMap заботится о памяти самостоятельно. Не нужно вручную удалять данные, когда объект становится ненужным — это происходит автоматически.
С WeakMap работают всего четыре метода:
- set(key, value)— добавляет пару ключ‑значение.
- get(key)— возвращает значение, связанное с ключом.
- has(key)— проверяет наличие ключа.
- delete(key)— удаляет пару ключ‑значение.
Пример использования:
const weakMap = new WeakMap();
let user = { name: "Alice" };
weakMap.set(user, "Приватные данные пользователя");
console.log(weakMap.get(user)); // "Приватные данные пользователя"
user = null;
// После этого объект автоматически удаляется из WeakMap сборщиком мусора.Примеры применения
WeakMap отлично подходит для хранения приватных данных внутри объектов, не изменяя их структуру.
const privateData = new WeakMap();
class User {
  constructor(name) {
    this.name = name;
    privateData.set(this, { permissions: [] });
  }
  getPermissions() {
    return privateData.get(this).permissions;
  }
  addPermission(permission) {
    privateData.get(this).permissions.push(permission);
  }
}
const user = new User("Bob");
user.addPermission("admin");
console.log(user.getPermissions()); // ["admin"]
// Если объект user будет удалён, его данные из privateData также исчезнут.А если ваш код обрабатывает объекты, и нужно сохранять результаты обработки, WeakMap позволяет это сделать без риска утечек памяти.
const cache = new WeakMap();
function processData(obj) {
  if (cache.has(obj)) {
    return cache.get(obj); // Используем закэшированные данные
  }
  // Сложные вычисления
  const result = { processed: true };
  cache.set(obj, result);
  return result;
}
let data = { id: 1 };
console.log(processData(data)); // { processed: true }
console.log(processData(data)); // { processed: true }
data = null; // Кэш автоматически очищается.WeakSet
WeakSet — это коллекция только объектов, которые хранятся по слабым ссылкам. Как и в случае с WeakMap, если объект становится недостижимым, он автоматически удаляется из WeakSet.
Основное предназначение WeakSet — отслеживание уникальных объектов без риска их «залипания» в памяти.
Методов у WeakSet ещё меньше, чем у WeakMap:
- add(value)— добавляет объект.
- has(value)— проверяет наличие объекта.
- delete(value)— удаляет объект.
Пример использования:
const weakSet = new WeakSet();
let obj = { id: 1 };
weakSet.add(obj);
console.log(weakSet.has(obj)); // true
obj = null;
// Объект автоматически удаляется из WeakSet.Примеры применения
Например, нужно гарантировать, что каждый объект обрабатывается только один раз:
const processed = new WeakSet();
function process(obj) {
  if (processed.has(obj)) {
    console.log("Объект уже обработан!");
    return;
  }
  processed.add(obj);
  console.log("Обрабатываю объект:", obj);
}
let task = { id: 1 };
process(task); // "Обрабатываю объект"
process(task); // "Объект уже обработан!"
task = null; // WeakSet автоматически очищается.Так же, работая с DOM, можно использовать WeakSet для отслеживания элементов, которым уже назначены обработчики событий:
const elementsWithHandlers = new WeakSet();
function addClickHandler(element) {
  if (!elementsWithHandlers.has(element)) {
    elementsWithHandlers.add(element);
    element.addEventListener("click", () => console.log("Клик!"));
  }
}
let div = document.createElement("div");
addClickHandler(div); // Привязываем обработчик
addClickHandler(div); // Ничего не делаем, обработчик уже добавлен
div = null; // Обработчики удаляются автоматически.Хотя использование этих инструментов может показаться ограниченным, они становятся незаменимыми, когда вы работаете с кэшами, приватными данными или сложными DOM‑структурами.
Если есть опыт применения этих инструментов, пишите в комментариях!
Все актуальные инструменты и лучшие практики веб‑разработки можно изучить на онлайн‑курсах в Otus. В каталоге можно посмотреть список всех программ, а в календаре мепроприятий — записаться на бесплатные открытые уроки.
 
          