تفاوت بین ()forEach و ()map که هر توسعه دهنده باید بداند

ترجمه و تالیف : فاطمه شیرزادفر
تاریخ انتشار : 03 فروردین 99
خواندن در 2 دقیقه
دسته بندی ها : جاوا اسکریپت

جاوااسکریپت روش‌های مفیدی دارد که بتوانیم آرایه‌هایمان را با آن‌ها پیمایش کنیم.دو تا از روش‌های معمول که برای پیمایش آرایه‌ها استفاده می‌شود Array.prototype.map() و Array.prototype.forEach() هستند.

اما من فکر می‌کنم که این دو روش کمی مبهم هستند، به خصوص برای افراد تازه کار. چون هر دوی آن‌ها آرایه را پیمایش می‌کنند و خروجی می‌دهند. خوب، پس این دو چه تفاوتی دارند؟

در این مقاله به چند مورد از ویژگی‌ها و تفاوت‌های این دو خواهم پرداخت :

  • تعاریف
  • مقدار برگشتی (returning value )
  • قابلیت chain (زنجیر) کردن متدهای دیگر
  • تغییرپذیری
  • سرعت عملکرد
  • حرف آخر

تعاریف

متد map یک فانکشن را به عنوان پارامتر دریافت می‌کند، سپس آن را بر روی هر یک از عناصر اعمال می‌کند و آرایه‌ای کاملاً جدید، با حاصلی که از فراخوانی همان فانکشن بوده را، باز می‌گرداند.

این به بدان معنی است که map یک آرایه‌ی جدید را باز می‌گرداند، که image هریک از عناصر آرایه است، و همیشه هم،‌ همان تعداد item را برمی‌گرداند.

const myAwesomeArray = [5, 4, 3, 2, 1]

myAwesomeArray.map(x => x * x)

// >>>>>>>>>>>>>>>>> Output: [25, 16, 9, 4, 1]

مثل map ،‌متد ()forEach هم یک تابع را به عنوان یک آرگومان دریافت می‌کند،‌و یک‌بار آن را برای هر یک از عناصر آرایه اجرا می‌‌‌کند. با این حال، به جای return یک آرایه جدید همانندundefined ،map برمی‌گرداند.

const myAwesomeArray = [
  { id: 1, name: "john" },
  { id: 2, name: "Ali" },
  { id: 3, name: "Mass" },
]

myAwesomeArray.forEach(element => console.log(element.name))
// >>>>>>>>> Output : john
//                                       Ali
//                                       Mass

۱.مقدار برگشتی (returning value )

اولین تفاوت بین ()map و ()forEach، مقداری است که return می‌شود. متد ()undefined ، forEach برمی‌گرداند و ()map یک آرایه‌ی جدید را،‌ با عناصری که گرفته باز می‌گرداند.

حتی اگر این دو متد،‌کار یکسانی را انجام دهند،‌ اما مقداری که بازمی‌گردانند متفاوت است.

const myAwesomeArray = [1, 2, 3, 4, 5]
myAwesomeArray.forEach(x => x * x)
//>>>>>>>>>>>>>return value: undefined

myAwesomeArray.map(x => x * x)
//>>>>>>>>>>>>>return value: [1, 4, 9, 16, 25]

۲.قابلیت chain کردن متدهای دیگر

تفاوت دوم بین این دو متدهای آرایه، این است که ()map قابلیت chain کردن دارد. به عبارت دیگر، شما می‌توانید بعد از اجرای متد  ()map روی یک آرایه، متدهای دیگر مثل ()reduce(), sort(), filter را نیز به آن متصل کنید.

این چیزی است که با متد ()forEach، نمی‌توان انجام داد. بله ،‌چون همان‌طور که حدس می‌زنید، undefined بر‌می‌گرداند.

const myAwesomeArray = [1, 2, 3, 4, 5]
myAwesomeArray.forEach(x => x * x).reduce((total, value) => total + value)
//>>>>>>>>>>>>> Uncaught TypeError: Cannot read property 'reduce' of undefined
myAwesomeArray.map(x => x * x).reduce((total, value) => total + value)
//>>>>>>>>>>>>>return value: 55

۳.تغییر پذیری

به طور‌کلی،‌ کلمه‌ی ’mutate’ به معنای تغییر،‌ اصلاح یا تغییر شکل است.و در دنیای جاوااسکریپت هم همین معنا را دارد.

Object قابل تغییر، آبجکتی است که حالت آن می‌تواند بعد از ایجاد شدن، تغییر کند. خب پس در رابطه باforEach وmap ، تغییرپذیری چه معنایی دارد؟

طبق مستندات MDN :

 ()forEach نمی‌تواند یک آرایه، که فراخوانی شده است را تغییر دهد(با این حال ممکن است برای callback این اتفاق بیفتد.)

 ()map هم نمی‌تواند آرایه‌ای را که فراخوانی شده،‌تغییر دهد(البته ممکن است برای callback ، اگر invoke شود ،‌این اتفاق بیفتد.)

بله خب، جاوا اسکریپت یکم عجیبه!!

در این‌جا ، تعریف بسیار مشابهی را می‌بینیم، و همه‌ی ما می‌دانیم که هر دوی آن‌ها یک callback رابه عنوان آرگومان دریافت می‌کنند. پس کدام یک تغییرناپذیر هستند؟

البته،‌به نظر من این تعریف هم هنوز مشخص نیست، و برای این‌که بدانیم کدام‌یک، آرایه اصلی را تغییر نمی‌دهد، ابتدا باید چگونگی عملکرد این دو متد را بررسی کنیم.

متد ()map،‌یک آرایه‌ی کاملاً جدید را با عناصر تبدیل شده (المان‌هایی که تغییر شکل پیدا کرده‌اند) و با همان مقدار داده، برمی‌گرداند. اما درمورد ()forEach حتی اگر undefined برگرداند، آرایه‌ی اصلی را با callback، تغییر می‌دهد.

بنابراین، ما به وضوح می‌بینیم که ()map،‌تغییرناپذیر است اما ()forEach،یک متد تغییرپذیر است.

۴.سرعت عملکرد

سرعت عمل‌کرد این دو متد کمی متفاوت است. اما آیا این مسئله مهم است؟

خب، این امر به موارد مختلفی مانند رایانه شما، میزان داده‌ای که با آن سروکار دارید و موارد دیگری بستگی دارد.

شما خودتان می‌توانید با استفاده از مثال زیر یا jsPerf ، ببینید کدام سریع‌تر است؟

const myAwesomeArray = [1, 2, 3, 4, 5]
const startForEach = performance.now()
myAwesomeArray.forEach(x => (x + x) * 10000000000)
const endForEach = performance.now()
console.log(`Speed [forEach]: ${endForEach - startForEach} miliseconds`)

const startMap = performance.now()
myAwesomeArray.map(x => (x + x) * 10000000000)
const endMap = performance.now()
console.log(`Speed [map]: ${endMap - startMap} miliseconds`)

حرف آخر

مثل همیشه، انتخاب بین ()map و ()forEach به مورد استفاده شما بستگی دارد. اگر قصد دارید ،‌داده‌ها را تغییر دهید ، alternate کنید یا از آن استفاده کنید،‌باید متد map را انتخاب کنید. چراکه یک آرایه جدید با داده‌هایی که تبدیل شده‌اند را باز می‌گرداند.

اما اگر به آرایه بازگشتی (returning array) احتیاج ندارید، از map استفاده نکنید و به جای آن از forEach یا حتی یک حلقه for استفاده کنید.

امیدوارم این مقاله، تفاوت‌های بین این دو متد را برای شما روشن کرده باشد.اگر تفاوت‌های بیش‌تری وجود دارد که من آن را نگفتم،‌لطفا در بخش نظرات به اشتراک بگذارید.

 از این که برای مطالعه این مقاله وقت گذاشتید ممنونم.

منبع

گردآوری و تالیف فاطمه شیرزادفر
آفلاین
user-avatar

تجربه کلمه‌ای هست که همه برای توصیف اشتباهاتشون ازش استفاده میکنن، و من همیشه دنبال اشتباهات جدیدم! برنامه‌نویس هستم و لینوکس‌ دوست

دیدگاه‌ها و پرسش‌ها

برای ارسال نظر لازم است ابتدا وارد سایت شوید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید