レッスンに戻る

「未読」フラグを格納する

重要度:5

メッセージの配列があります

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

コードからアクセスできますが、メッセージは他の人のコードによって管理されます。新しいメッセージが追加され、古いメッセージはそのコードによって定期的に削除され、それがいつ行われるかは正確にわかりません。

では、メッセージが「読まれた」かどうかについての情報を格納するために使用できるデータ構造はどれでしょうか。その構造は、指定されたメッセージオブジェクトに対して「それは読まれたのか」という答えを出すのに適している必要があります。

P・S・メッセージがmessagesから削除されると、あなたの構造からも消えるはずです。

P・P・S・メッセージオブジェクトを変更したり、プロパティを追加したりすることはできません。それらは他のコードによって管理されているため、悪い結果を招く可能性があります。

「既読」メッセージをWeakSetに格納しましょう

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

let readMessages = new WeakSet();

// two messages have been read
readMessages.add(messages[0]);
readMessages.add(messages[1]);
// readMessages has 2 elements

// ...let's read the first message again!
readMessages.add(messages[0]);
// readMessages still has 2 unique elements

// answer: was the message[0] read?
alert("Read message 0: " + readMessages.has(messages[0])); // true

messages.shift();
// now readMessages has 1 element (technically memory may be cleaned later)

WeakSetはメッセージのセットを格納し、その中でメッセージの存在を簡単にチェックできます。

自動的にクリーンアップされます。トレードオフは、それを反復処理したり、直接「すべての既読メッセージ」を取得したりできないことです。ただし、すべてのメッセージを反復処理してセット内のメッセージをフィルター処理することで実現できます。

別の解決策として、メッセージが読まれた後にmessage.isRead=trueのようなプロパティをそのメッセージに追加できます。メッセージオブジェクトは別のコードによって管理されるため、一般的には推奨されませんが、シンボルプロパティを使用して競合を回避できます。

以下のように

// the symbolic property is only known to our code
let isRead = Symbol("isRead");
messages[0][isRead] = true;

これで、サードパーティのコードはおそらく私たちの追加のプロパティを見ることはないでしょう。

シンボルを使用すると問題の確率を下げられますが、アーキテクチャの観点からはWeakSetを使用するほうが優れています。