hellojs.ru
Главная - JavaScript в работе - WeakMap и WeakSet

WeakMap и WeakSet

Размещено в категории "JavaScript в работе"
06.11.2024 / просмотров: 33 / комментариев: 0
Ресурсы:

Документация 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 вышла из чата:

Код

lena = null;

Получается этот объект исчез, а ссылка на него существовала только внутри слабой карты, поэтому этот объект автоматически удалится из памяти.

Проверяем:

Код

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, например, первый:

Код

messages.shift();

Теперь внутри нашего кода на этот объект нет никаких ссылок и он хранится только внутри WeakSet, он этот понимает и дает команду сборщику мусора удалить этот объект.

И если мы сейчас это проверим, то получим false:

Код

console.log(readMessages.has(messages[0])); // false

Минус этой структуры данных в том, что мы не можем перебрать его содержимое, не можем узнать, какие сообщения там содержатся, не можем их все получить напрямую или какое-то одно из них.

Цитата

WeakMap и WeakSet являются дополнительными хранилищами данных для объектов, управляемых с каких-то других мест в коде, и если на них нет никаких ссылок и они содержатся только в этих структурах, то они будут удалены из памяти.
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
Сайт управляется системой uCoz