儲存「未讀」旗標
重要性: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
更好。