Ответ
Weak Reference (слабая ссылка) — это ссылка на объект, которая не защищает этот объект от сборки мусора (Garbage Collection). Если на объект остались только слабые ссылки, сборщик мусора может удалить его, и слабые ссылки автоматически станут undefined (или коллекция их очистит).
В JavaScript слабые ссылки реализованы через две встроенные коллекции: WeakMap и WeakSet.
Ключевые отличия от Map и Set:
- Ключами могут быть только объекты (не примитивы).
- Нет итераторов. Нельзя получить список всех ключей или значений (
keys(),values(),entries()), нет свойстваsize. Это связано с тем, что перебор зависит от состояния сборки мусора, которое недетерминировано. - Автоматическая очистка. Если объект-ключ удалён сборщиком мусора, запись автоматически удаляется из
WeakMap, а объект — изWeakSet.
Практическое применение WeakMap:
Часто используется для хранения приватных или вспомогательных данных объекта, не вмешиваясь в его жизненный цикл и не вызывая утечек памяти.
// Пример: хранение приватных метаданных для объектов
const privateData = new WeakMap();
class User {
constructor(name) {
// this - объект, используем его как ключ в WeakMap
privateData.set(this, {
name: name,
secretToken: Math.random().toString(36).substr(2)
});
}
getName() {
// Получаем данные по ссылке на текущий экземпляр
return privateData.get(this).name;
}
}
let user = new User('Анна');
console.log(user.getName()); // 'Анна'
console.log(privateData.get(user)); // { name: 'Анна', secretToken: '...' }
// Когда объект user будет удалён (например, вышел из области видимости),
// запись в WeakMap также будет автоматически удалена сборщиком мусора.
// Это предотвращает утечку памяти.
user = null;
// Теперь privateData не удерживает старый объект в памяти.
WeakSet используется аналогично для хранения наборов объектов (например, для отслеживания, был ли объект обработан), не препятствуя их удалению.
Ответ 18+ 🔞
Давай разберём эту тему, а то некоторые до сих пор думают, что WeakMap — это карта для слабаков. Ёпта, нет же.
Смотри, представь обычную ссылку на объект — это как железная хватка. Пока ты за него держишься, сборщик мусора (этот дворник памяти) мимо пройдёт и подумает: «А, жилой, окей». А слабая ссылка — это как взять того же чувака за рукав, но так, не особо цепко. Если он сам решит свалить (или его другие железные хватки отпустят), то он свалит, а твоя рука просто повиснет в воздухе, и ссылка станет undefined. Вот и вся магия. Объект могут почистить, если на него только слабые ссылки остались.
В JavaScript это реализовано в двух коллекциях: WeakMap и WeakSet. И у них, в отличие от их тупых братьев Map и Set, есть три главные фишки, от которых терпения ноль ебать у тех, кто ждёт от них обычного поведения:
- Ключи — только объекты. Не суй туда строки, числа или свою надежду на светлое будущее. Только объекты. Иначе получишь чих-пых тебя в сраку, то есть ошибку.
- Нет итераторов и
size. Нельзя пройтисьforEach, нельзя получитьkeys(). Доверия ебать ноль у движка к состоянию сборки мусора, оно нестабильное. Поэтому он тебе и не даёт эти методы, чтобы ты не охуел, когда ключи на половине перебора вдруг испарятся. - Автоматическая зачистка. Это главная фишка. Удалили объект из памяти — запись из
WeakMapилиWeakSetсама исчезнет. Никаких утечек памяти, красота.
Зачем этот WeakMap вообще нужен?
Чаще всего — чтобы привязать к объекту какие-то приватные данные, но так, чтобы не мешать ему умирать. Классический пример — эмуляция приватных полей в классе, когда тебе подозрение ебать чувствую, что лезть в публичные свойства — плохая идея.
Смотри, как это выглядит на практике:
// Создаём наш тайный склад данных. Это WeakMap.
const secretStorage = new WeakMap();
class Person {
constructor(name) {
// this — это и есть сам объект (например, {Person: ...}).
// Используем его как КЛЮЧ в нашей тайной карте.
// А значением кладём объект с данными, которые хотим спрятать.
secretStorage.set(this, {
name: name,
secretCode: 'ХУЙ' + Math.random() // Ну или что-то посерьёзнее
});
}
getName() {
// Чтобы прочитать приватные данные, просто достаём их по ключу this.
// То есть по ссылке на текущий экземпляр.
return secretStorage.get(this).name;
}
}
let person = new Person('Василий');
console.log(person.getName()); // 'Василий'
console.log(secretStorage.get(person)); // { name: 'Василий', secretCode: 'ХУЙ0.abc123' }
// А теперь магия! Убиваем ссылку на объект.
person = null;
// Ждём сборки мусора (в реальности не сразу, но факт)...
// И запись, связанная с УДАЛЁННЫМ объектом, АВТОМАТИЧЕСКИ исчезнет из secretStorage!
// Память почистилась, утечки нет. Это и есть **овердохуища** полезно.
А WeakSet?
С ним ещё проще. Это как клуб по интересам, куда записывают объекты. Используют, чтобы отмечать, что объект уже был обработан (например, посещённая нода в графе). И если объект удалили из программы, он автоматом выбывает из клуба. Удобно, я тебе скажу.
Короче, суть в чём: используй WeakMap/WeakSet, когда нужно привязать данные или метку к жизни объекта, но сам от себя охуел бы от мысли, что из-за твоих данных объект будет вечно висеть в памяти. Для всего остального — обычные Map и Set.