September 8, 2023

Решение задачи

Тема: WeakMap и WeakSet в JavaScript

Решение:

Можно хранить прочитанные сообщения в WeakSet:

let messages = [
    {text: "Hello", from: "John"},
    {text: "How goes?", from: "John"},
    {text: "See you soon", from: "Alice"}
];

let readMessages = new WeakSet();

// Два сообщения были прочитаны
readMessages.add(messages[0]);
readMessages.add(messages[1]);
// readMessages содержит 2 элемента

// ...давайте снова прочитаем первое сообщение!
readMessages.add(messages[0]);
// readMessages до сих пор содержит 2 элемента

// Вопрос: было ли сообщение message[0] прочитано?
alert("Read message 0: " + readMessages.has(messages[0])); // true

messages.shift();
// теперь readMessages содержит 1 элемент (хотя технически память может быть очищена позже)

WeakSet позволяет хранить набор сообщений и легко проверять наличие сообщения в нём.

Он очищается автоматически. Минус в том, что мы не можем перебрать его содержимое, не можем получить «все прочитанные сообщения» напрямую. Но мы можем сделать это, перебирая все сообщения и фильтруя те, которые находятся в WeakSet.

Альтернативным решением может быть добавление свойства вида message.isRead=true к сообщению после его прочтения. Так как сообщения принадлежат чужому коду, то это не очень хорошо, но если использовать свойство-символ, то вероятность конфликтов будет небольшой.

Например:

// символьное свойство вместо имени, которое известно только нашему коду
let isRead = Symbol("isRead");
messages[0][isRead] = true;

Теперь чужой код вряд ли увидит наше дополнительное свойство.

Хотя символы и позволяют уменьшить вероятность проблем, использование здесь WeakSet лучше с архитектурной точки зрения.