بازگشت به درس

پرچم‌های «خوانده نشده» را ذخیره کنید

اهمیت: 5

یک آرایه از پیام‌هایی داریم:

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

کد شما می‌تواند به آن دسترسی پیدا کند اما پیام‌ها توسط کد شخص دیگری مدیریت می‌شود. پیام‌های جدید اضافه می‌شوند و قدیمی‌ها توسط آن کد به طور منظم حذف می‌شوند و شما نمی‌دانید دقیقا کی اتفاق می‌افتد.

حالا شما کدام ساختار داده را استفاده می‌کنید تا اطلاعاتی درباره اینکه پیام «خوانده شده یا نه» را دخیره کنید؟ ساختار باید برای جواب دادن به این سوال که «آیا خوانده شد؟» برای شیء داده شده به خوبی پاسخ دهد.

پی‌نوشت: زمانی که یک پیام از messages حذف شود، باید از ساختار شما هم حذف شود.

پی‌نوشت دوم: ما نباید شیء‌های پیام را تغییر دهیم یا ویژگی‌های خودمان را به آنها اضافه کنیم. به دلیل اینکه آنها توسط کد شخص دیگری کنترل می‌شوند، این کار ممکن است نتایج بدی داشته باشد.

بیایید پیام‌های خوانده شده را در 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

// !بیایید اولین پیام را دوباره بخوانیم...
readMessages.add(messages[0]);
// همچنان دو المان یکتا دارد readMessages

// خوانده شده است؟ message جواب: آیا
alert("Read message 0: " + readMessages.has(messages[0])); // true

messages.shift();
// یک المان دارد (از لحاظ فنی، حافظه ممکن است بعدا از آن المان تمیز شود) readMessages حالا

ساختار WeakSet به ما این امکان را می‌دهد که یک دسته از پیام‌ها را ذخیره کنیم و به راحتی بررسی کنیم که پیامی درون آن هست یا نه.

این ساختار به طور خودکار محتوای دورنش را پاک می‌کند. اما بدی آن این است که ما نمی‌توانیم درون آن حلقه بزنیم، نمی‌توانیم به طور مستقیم «تمام پیام‌های خوانده شده» را از آن بگیریم. اما می‌توانیم این کار را با حلقه‌زدن درون تمام پیام‌ها و جداسازی آن‌هایی که درون set هستند، انجام دهیم.

یک راه حل متفاوت دیگر می‌تواند اضافه کردن ویژگی message.isRead=true به پیام، بعد از اینکه خوانده شد باشد. به دلیل اینکه شیءهای پیام‌ها توسط کد دیگری انجام می‌شود، این کار توصیه نمی‌شود اما می‌توانیم از ویژگی سمبلی برای جلوگیری از تناقضات استفاده کنیم.

مثلا اینگونه:

// ویژگی سمبلی تنها در کد ما شناخته شده است
let isRead = Symbol("isRead");
messages[0][isRead] = true;

حالا کد شخص ثالث احتمالا ویژگی اضافی ما را نخواهد دید.

اگرچه سمبل‌ها به ما این امکان را می‌دهند که از احتمال بروز مشکل را کم کنیم، استفاده از WeakSet از نظر معماری بهتر است.