Map و Set: ساختارهای داده‌ی مدرن فراتر از آرایه و شیء

تا این‌جا برای نگهداری داده از شیء (object) و آرایه (array) استفاده کرده‌اید. اما جاوااسکریپت دو ساختار داده‌ی مدرن‌تر نیز ارائه می‌دهد که برای نیازهای خاصی طراحی شده‌اند: Map برای نگهداری جفت‌های کلید-مقدار با کلیدهایی از هر نوع، و Set برای نگهداری مجموعه‌ای از مقادیر یکتا. هر دو ساختار مشکلاتی از شیء و آرایه‌ی معمولی را برطرف می‌کنند که در ادامه بررسی خواهد شد.

محدودیت شیء معمولی به‌عنوان نگهدارنده‌ی کلید-مقدار

شیء معمولی برای نگهداری جفت‌های کلید-مقدار رایج است، اما دو محدودیت مهم دارد: کلیدها همیشه به رشته یا Symbol تبدیل می‌شوند (حتی اگر عدد یا شیء دیگری پاس داده شود)، و شمارش تعداد ویژگی‌ها نیازمند متدهایی مثل Object.keys است، نه یک ویژگی مستقیم مثل طول آرایه.

Map: کلیدهایی از هر نوع، با API اختصاصی

Map این محدودیت‌ها را برطرف می‌کند. کلید یک Map می‌تواند هر نوع داده‌ای باشد، از جمله شیء، تابع یا حتی آرایه، بدون آنکه به رشته تبدیل شود:

کار پایه با Map
خروجی کنسول اینجا نمایش داده می‌شود...

همان‌طور که مشاهده می‌کنید، Map متدهای اختصاصی و معنادار خودش را دارد: set برای افزودن، get برای خواندن، has برای بررسی وجود کلید، و delete برای حذف؛ همچنین ویژگی size به‌طور مستقیم تعداد عناصر را برمی‌گرداند، برخلاف شیء معمولی که نیاز به Object.keys(obj).length دارد.

پیمایش Map با for...of

از آنجا که Map یک ساختار Iterable است (مفهومی که در فصل ۱۹ بررسی شد)، مستقیماً با for...of قابل پیمایش است و هر عنصر آن به‌صورت یک آرایه‌ی دو‌عضوی [key, value] بازگردانده می‌شود:

for (const [key, value] of userRoles) {
  console.log(key, "->", value);
}

Set: مجموعه‌ای از مقادیر یکتا

Set ساختاری برای نگهداری مجموعه‌ای از مقادیر است که هر مقدار فقط یک‌بار می‌تواند در آن وجود داشته باشد. تلاش برای افزودن مقداری که قبلاً وجود دارد، هیچ تأثیری ندارد و خطایی هم تولید نمی‌کند:

const tags = new Set();

tags.add("جاوااسکریپت");
tags.add("وب");
tags.add("جاوااسکریپت"); // این مقدار تکراری نادیده گرفته می‌شود

console.log(tags.size);          // 2
console.log(tags.has("وب"));     // true

tags.delete("وب");
console.log(tags.size); // 1

کاربرد رایج Set: حذف مقادیر تکراری از آرایه

یکی از پرکاربردترین موارد استفاده‌ی Set، حذف سریع مقادیر تکراری از یک آرایه است؛ با ترکیب Set و عملگر spread، این کار در یک خط انجام می‌شود:

const numbers = [1, 2, 2, 3, 4, 4, 4, 5];

const uniqueNumbers = [...new Set(numbers)];
console.log(uniqueNumbers); // [1, 2, 3, 4, 5]

جدول مقایسه‌ی Map/Set با Object/Array

ویژگی Object Map
نوع کلید مجاز فقط رشته یا Symbol هر نوعی، از جمله شیء و تابع
دریافت تعداد عناصر Object.keys(obj).length ویژگی مستقیم size
ترتیب پیمایش در اکثر موارد حفظ می‌شود، اما تضمین‌شده نیست همیشه به ترتیب افزودن تضمین‌شده است
ویژگی Array Set
مقادیر تکراری مجاز است به‌طور خودکار حذف می‌شوند
بررسی وجود یک مقدار includes (با پیچیدگی زمانی خطی) has (معمولاً سریع‌تر برای مجموعه‌های بزرگ)

نکات کلیدی

  • Map برخلاف شیء معمولی، اجازه می‌دهد کلیدهایی از هر نوع، از جمله شیء و تابع، استفاده شوند.
  • ویژگی size در Map و Set، تعداد عناصر را مستقیماً و بدون نیاز به متد جداگانه برمی‌گرداند.
  • Set هر مقدار را فقط یک‌بار نگه می‌دارد و برای حذف مقادیر تکراری از آرایه بسیار کاربردی است.
  • هر دو ساختار Iterable هستند و مستقیماً با for...of قابل پیمایش‌اند.

جمع‌بندی

Map و Set دو ساختار داده‌ی تخصصی هستند که محدودیت‌های شیء و آرایه‌ی معمولی را در سناریوهای خاص برطرف می‌کنند: Map برای نگهداری کلید-مقدار با کلیدهایی از هر نوع، و Set برای نگهداری مجموعه‌ای از مقادیر یکتا. هر دو با API اختصاصی و روشن خود (set/get/has/delete برای Map و add/has/delete برای Set) و پشتیبانی کامل از پیمایش با for...of، ابزارهایی طبیعی برای بسیاری از الگوهای رایج برنامه‌نویسی محسوب می‌شوند.