WeakMap и WeakSet

Допустим, у нас есть какой-то объект с данными:

Код
let user = {name: 'Ivan'};

И на каком-то этапе user примет значение null

Код
user = null;

Если мы сейчас выведем в консоль содержимое user, то получим null, объект в памяти больше не существует, на него нет никаких ссылок.

Но, если в наш код мы добавим массив, в котором будет лежать ссылка на объект user, далее также присвоим для user значение null и выведем в консоль user и первый элемент массива arr

Код
let user = {name: 'Ivan'};

const arr = [user];

user = null;

console.log(user); // null
console.log(arr[0]); // { name: 'Ivan' }

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

По аналогии будет с картой (Map), пока карта существует, объект будет храниться в памяти.

Код
let user = {name: 'Ivan'};

let map = new Map();

map.set(user, 'data');

user = null;

console.log(map.keys());

Цитата
[Map Iterator] { { name: 'Ivan' } }

Опять мы видим, что хоть мы и удалили объект через присвоение ему значения null (строка 7), за счет того, что в карте осталась ссылка на этот объект (строка 5), он будет продолжать храниться в памяти.

WeakMap - или "слабая карта"

а) ключами в ней могут быть только объекты

б) если нет ссылки на объект, который существует только внутри WeakMap, он будет удалён из этой карты

Код
let user = {name: 'Ivan'};

let map = new WeakMap(); // создали слабую карту

map.set(user, 'data');

user = null;

console.log(map.has(user)); // false

Для WeakMap доступны лишь методы set(), get(), delete(), has()

Для использования WeakMap нужны определённые условия, например, временное хранилище объектов в работе сайта или приложения или кэшировании данных.

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

Создадим новую карту WeakMap, изначально пустую, а также функцию, которая будет кэшировать(запоминать) каждого нового пользователя, который вошел в чат и запоминать его в карте, если же пользователь покидает чат, то он удаляется из карты.

Код
let cashe = new WeakMap();

function casheUser(user) {
  if (!cashe.has(user)) {
  cashe.set(user, Date.now());
  }

  return cashe.get(user);
}

Создадим нескольких пользователей:

Код
let lena = {name: 'Elena'};
let alex = {name: 'Alex'};

Допустим, оба этих пользователя вошли в чат:

Код
// пользователи вошли в чат  

casheUser(lena);
casheUser(alex);

В какой-то момент времени Елена вышла из чата:

Код
lena = null

Получается, объект lena удалён (null), а так как ссылка на его была только внутри WeakMap, то и в памяти он будет очищен.

Проверим это, выведем в консоль результат проверки, есть ли такой объект lena в WeakMap

Код
console.log(cashe.has(lena)); // false
console.log(cashe.has(alex)); // true

WeakSet - данная коллекция аналогична обычному Set, но в WeakSeat можно добавлять только объекты.

WeakSet поддерживает методы add(), has() и delete(), метод get() не поддерживается.

Разбираем на примере сообщений в чате.

Допустим, у нас есть массив с объектами, в котором будут сообщения и информация от кого эти сообщения:

Код
let messages = [
  { text: "Hello", from: "John" },
  { text: "World", from: "Alex" },
  { text: "....", from: "M" }
];

Далее создадим новую структуру данных, содержащую уже прочитанные сообщения:

Код
let readMessages = new WeakSet();

При прочтении сообщений они добавляются в наш WeakSet

Код
// Прочитанные сообщения добавляются в наш набор

readMessages.add(messages[0]);
readMessages.add(messages[1]);

Проверим, есть ли в нашем наборе, к примеру, первое сообщение:

Код
console.log(readMessages.has(messages[0])); // true

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

Код
let messages = [
  { text: "Hello", from: "John" },
  { text: "World", from: "Alex" },
  { text: "....", from: "M" }
];

let readMessages = new WeakSet();

// Прочитанные сообщения добавляются в наш набор

readMessages.add(messages[0]);

messages.shift(); // удаляем первый элемент массива

// Проверяем, есть ли такой элемент в наборе

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


Документация WeakMapДокументация WeakSet

Всего комментариев: 0

Имя *:
Email *:
Код *:
Хостинг от uCoz