Что такое слабая ссылка в WeakSet и WeakMap в JavaScript
Что проверяют
Понимаете ли вы, как в JavaScript решается, что объект больше не нужен. Достижимость, сильные и слабые ссылки, утечки через коллекции и подписки это ежедневная тема браузерного кода, и слабые коллекции удобный повод её проверить.
Как отвечать
Сборщик мусора освобождает объект, до которого нельзя добраться по ссылкам от корней. Обычные Map и Set держат сильные ссылки, поэтому положенный в них объект живёт, пока жива коллекция, даже если больше нигде не нужен.
Слабая ссылка достижимости не даёт. WeakSet слабо держит свои элементы, WeakMap слабо держит ключи: не осталось других ссылок на объект, и запись уходит вместе с ним.
const meta = new WeakMap();
function attach(node, data) {
meta.set(node, data);
}
// узел убрали из DOM и забыли ссылку: запись в meta исчезнет самаОтсюда ограничения, их и спрашивают: ключами могут быть объекты, из примитивов в современных движках допустимы только незарегистрированные символы; нет size, нет перебора и очистки; момент удаления не наблюдаем. Иначе поведение программы зависело бы от момента работы сборщика мусора.
Практическое применение: приватные данные, привязанные к экземпляру, кэш вычисленного по узлу DOM, пометка уже обработанных объектов, метаданные подписок. Рядом стоит назвать WeakRef и FinalizationRegistry для случая, когда слабая ссылка нужна на один объект.
Где спотыкаются
Ждут немедленного освобождения. Присвоение null только убирает ссылку, а когда вернётся память, не определено, и писать тест на исчезновение записи бессмысленно.
Кладут строку или число ключом и получают ошибку типа. У примитива нет идентичности, привязывать данные не к чему, для такого случая нужна обычная Map.
Считают слабую коллекцию страховкой от любых утечек. Если ключ это долгоживущий объект, не освободится ничего, а значение держится сильно, пока жив ключ. Чаще всего течёт не коллекция, а неснятый обработчик или замыкание, удерживающее узел.