Ресурсы: Документация WeakMap Документация WeakSet
Данные структуры используются еще реже,чем обычные
Map или
Set и в основном служат для оптимизации кода.
Для начала создадим переменную и положим в неё объект с какими-то данными:
Код
let user = {name: 'Ivan'};
Допустим, в какой-то момент наш объект перезапишется в формат
null Код
user = null;
console.log(user); // null
Объект удалён из памяти, так как ссылок на него больше нет.
Но, если мы создадим массив и в него в качестве элемента запишем объект
user (ссылку на него)
Код
let user = {name: 'Ivan'};
const arr = [user];
user = null;
console.log(user); // null
console.log(arr[0]); // { name: 'Ivan' }
Так как объект хранится в памяти благодаря ссылке на него в массиве, то даже при перезаписи его в
null, массив имеет к нему доступ и поэтому мы видим его в консоли. Пока массив
arr существует, будет в памяти существовать и объект.
Тоже самое касается и карты: пока существует карта, будет лежать и объект в памяти. И иногда это очень невыгодно.
Разберём на примере, создадим новую карту, без какого-то значения:
Код
let user = {name: 'Ivan'};
let map = new Map(); // создаём новую карту
map.set(user, 'data'); // устанавливаем ключ и значение
user = null; // перезаписываем значение переменной
console.log(map.keys()); // возвращаем объект по ключам
И в консоли мы увидим объект, хотя он и был перезаписан на
null.
Цитата
[Map Iterator] { { name: 'Ivan' } }
WeakMap (слабая карта)
У данной структуры есть две особенности:
1. ключами в ней могут быть только объекты
2. если нет ссылки на объект и он существует только в
WeakMap, он будет удалён из этой слабой карты
Для примера превратим нашу карту из предыдущего кода в слабую карту:
Код
let user = {name: 'Ivan'};
let map = new WeakMap(); // создаём новую карту
map.set(user, 'data'); // устанавливаем ключ и значение
user = null; // перезаписываем значение переменной
console.log(map.has(user)); // проверяем есть ли такой объект
В консоли мы получим
false, а это значит, что объект был удалён автоматически
У
WeakMap не существует таких методов как
keys(), values(), entries(), её нельзя перебрать при помощи
for...of Доступны
set(), get(), has() и delete.
Для использования такой структуры нужны определённые условия, например, временные хранилища объектов в работе сайта или приложения, либо кэширование данных.
На примере с чатом, где в одном канале может сидеть множество людей и нам нужно хранить их всех для отображения, при этом кто-то входит в онлайн, кто-то выходит и всё это нужно также отслеживать:
Код
let cache = new WeakMap(); // создаём новую слабую карту
Далее создадим функцию, которая будет кэшировать пользователей(запоминать их), с проверкой условия, что если пользователь начинает заходить в чат, то он кэшируется и запоминается, если же он выходит из чата, он автоматически удаляется из памяти:
Код
function cacheUser(user) {
if (!cache.has(user)) { // если такого пользователя нет внутри нашей слабой карты, то
cache.set(user, Date.now()); // добавляем его и отслеживаем когда он вошел в чат
}
return cache.get(user);
}
Теперь создадим нескольких пользователей:
Код
let lena = {name: 'Elena'};
let alex = {name: 'Alex'};
Оба этих пользователя вошли в чат, поэтому мы используем функцию
cacheUser с этими объектами:
Код
cacheUser(lena);
cacheUser(alex);
Допустим, в какой-то момент времени
lena вышла из чата:
Получается этот объект исчез, а ссылка на него существовала только внутри слабой карты, поэтому этот объект автоматически удалится из памяти.
Проверяем:
Код
console.log(cache.has(lena)); // false
console.log(cache.has(alex)); // true
WeakSet
- коллекция аналогична обычному
Set, но добавлять в неё мы можем только объекты.
По аналогии, если какой-то объект находится только внутри
WeakSet, то он будет удалён из памяти.
WeakSet поддерживает такие методы, как
add(), has() и delete, но не поддерживает метод
get() (напрямую какое-то значение получить не можем, а только можем проверить наличие каких-то данных в формате "
да - нет").
Разберём на примере сообщений в чате:
Код
let messages = [
{text: 'Hello', from: 'John'},
{text: 'World', from: 'Alex'},
{text: '...', from: 'M'}
];
let readMessages = new WeakSet(); // прочитанные сообщения
При работе с чатом вы прочитываете какие-то сообщения:
Код
readMessages.add(messages[0]); // сообщение попало в прочитанные
readMessages.add(messages[1]); // сообщение попало в прочитанные
WeakSet позволяет нам хранить набор каких-то данных, легко проверять наличие каких-то данных в наборе
Код
console.log(readMessages.has(messages[0])); // true
Повторная команда
Код
readMessages.add(messages[0]);
не запишет дубликат данных, поскольку
WeakSet хранит уникальные данные.
Если удалить какой-то объект из массива
messages, например, первый:
Теперь внутри нашего кода на этот объект нет никаких ссылок и он хранится только внутри
WeakSet, он этот понимает и дает команду сборщику мусора удалить этот объект.
И если мы сейчас это проверим, то получим
false:
Код
console.log(readMessages.has(messages[0])); // false
Минус этой структуры данных в том, что мы не можем перебрать его содержимое, не можем узнать, какие сообщения там содержатся, не можем их все получить напрямую или какое-то одно из них.
Цитата
WeakMap и WeakSet являются дополнительными хранилищами данных для объектов, управляемых с каких-то других мест в коде, и если на них нет никаких ссылок и они содержатся только в этих структурах, то они будут удалены из памяти.
Добавлять комментарии могут только зарегистрированные пользователи.