احتمالاً برای شما هم پیش آمده که بخواهید روی یک آرایه پیمایش کنید و ناگهان با منوی باز جاوااسکریپت روبهرو میشوید: for معمولی بنویسم؟ map کنم؟ forEach بزنم؟ یا از for...of و for...in استفاده کنم؟
در نگاه اول شاید بگویید: «همهشون یه کار رو میکنن، چه فرقی داره؟» اما در یک مصاحبه فنی بینالمللی یا در Code Review های شرکتهای بزرگ (مثل FAANG)، انتخاب حلقه اشتباه میتواند باعث رد شدن کد شما شود! در این مقاله قصد داریم این حلقهها را کالبدشکافی کنیم تا دیگر هرگز در انتخاب آنها شک نکنید.
for: پیرمرد پرسرعتاین همان حلقهای است که از زبان C به ارث بردهایم.
content_copy javascriptconst arr = [10, 20, 30]; for (let i = 0; i < arr.length; i++) { if (arr[i] === 20) break; console.log(arr[i]); }
کی استفاده کنیم؟
وقتی پرفورمنس (Performance) در بالاترین حد اهمیت است (مثلاً در الگوریتمهای پیچیده با پیچیدگی زمانی O(n) یا بالاتر).
وقتی نیاز دارید وسط کار با break از حلقه خارج شوید یا با continue از یک مرحله بپرید.
وقتی گامهای حرکت شما خاص است (مثلاً دو تا دو تا جلو رفتن: i += 2).
چرا در کد روزمره کمتر استفاده میشود؟
چون Boilerplate (کد تکراری) زیادی دارد و احتمال خطای “Off-by-one” (اشتباه در شرط < یا <=) در آن بالاست.
forEach: کارگر بیادعا (Side Effects)متد forEach یک تابع میگیرد و آن را روی تکتک اعضای آرایه اجرا میکند.
content_copy javascriptconst users = ['Ali', 'Sara', 'John']; users.forEach((user, index) => { console.log(`User ${index}: ${user}`); });
نکات حیاتی (خوراک مصاحبه):
راه فرار ندارید! شما نمیتوانید از forEach با دستور break خارج شوید. اگر از return داخل آن استفاده کنید، فقط شبیه به continue عمل میکند و به دور بعدی میرود.
تله Async/Await: اگر داخل forEach از await استفاده کنید، جاوااسکریپت منتظر تمام شدن آن نمیماند! برای کارهای Asynchronous، استفاده از forEach یک اشتباه مهلک است.
هدف اصلی: فقط زمانی از forEach استفاده کنید که قصد دارید تغییری در دنیای بیرون بدهید (Side Effect)، مثلاً ذخیره در دیتابیس یا لاگ گرفتن.
map: کارخانه تبدیلمتد map سلطان برنامهنویسی Functional در جاوااسکریپت است.
content_copy javascriptconst prices = [10, 20, 30]; const pricesWithTax = prices.map(price => price * 1.09); // pricesWithTax: [10.9, 21.8, 32.7]
تذکر جدی یک Tech Lead:
خیلی از برنامهنویسها برای تمیزتر شدن کد، به جای forEach از map استفاده میکنند، در حالی که اصلاً به خروجی آن نیازی ندارند!
متد map همیشه یک آرایه جدید در مموری میسازد. اگر فقط میخواهید روی دادهها پیمایش کنید و آرایه جدیدی نمیخواهید، استفاده از map باعث هدررفت حافظه (با پیچیدگی فضایی O(n)) میشود. map یعنی: «این آرایه را بگیر و یک آرایه جدید با همین تعداد عضو به من تحویل بده».
for...in: تلهای برای آرایهها!این حلقه برای پیمایش کلیدها (Keys) در یک Object طراحی شده است، نه مقادیر یک آرایه.
content_copy javascriptconst person = { name: 'John', age: 30 }; for (const key in person) { console.log(key, person[key]); }
چرا نباید روی آرایه از for...in استفاده کنیم؟
این حلقه روی ایندکسها به عنوان String پیمایش میکند ("0", "1") نه اعداد!
ترتیب اجرای آن در جاوااسکریپت تضمینشده نیست.
ممکن است پراپرتیهایی که به Prototype آرایه اضافه شدهاند را هم ناخواسته وارد حلقه کند.
خلاصه: for...in را فقط و فقط برای گشتن در دل Object ها استفاده کنید.
for...of: پادشاه مدرن جاوااسکریپت (ES6)این حلقه بهترین ترکیب از خوانایی و قدرت است و روی هر چیزی که Iterable باشد (آرایه، استرینگ، Map، Set) کار میکند.
content_copy javascriptconst numbers = [1, 2, 3]; for (const num of numbers) { if (num === 2) break; // به راحتی متوقف میشود console.log(num); }
چرا for...of فوقالعاده است؟
سینتکس بسیار تمیز و خوانایی دارد.
برخلاف forEach، از break و continue به خوبی پشتیبانی میکند.
بهترین گزینه برای پیمایشهای Asynchronous است (استفاده از for await...of).
برای اینکه در زمان کد زدن (یا مصاحبه) سریع تصمیم بگیرید، این جملات را گوشه ذهنتان بسپارید:
🔹 کلاسیک
for: وقتی الگوریتم پیچیده داری و پرفورمنس برات حیاتیه (محاسبات O(n2) و…).🔹
forEach: وقتی فقط میخوای یه کاری روی اعضا انجام بدی (Side Effect) و نیازی به توقف حلقه نداری.🔹
map: وقتی یک آرایه داری و میخوای از روی اون، یک آرایه جدید با همون طول بسازی (Transform).🔹
for...in: فقط برای گشتن روی کلیدهای یک Object (به آرایهها نزدیکش نکنید!).🔹
for...of: بهترین و تمیزترین راه پیشفرض برای پیمایش آرایهها (با قابلیت پشتیبانی از break و async).