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

یکشنبه 5 مرداد 1399

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

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

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

تعریف

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

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


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

myAwesomeArray.map(x => x * x)

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

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

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

1. مقدار بازگشتی

اولین تفاوت بین map() و forEach() مقدار بازگشتی است. متد forEach()، undefined را برمی‌گرداند و 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]

2. قابلیت زنجیروار کردن متدهای دیگر

دومین تفاوت بین متدهای آرایه این است که map() زنجیره‌ای است. این یعنی شما می‌توانید بعد از اجرای متد 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

3. تغییرپذیری

به طور کلی، تغییرپذیری یعنی تغییر، جایگزین، اصلاح یا تبدیل، و در دنیای جاوااسکریپت نیز همین معنی را دارد.

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

خوب، طبق مستندات MDN:

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

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

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

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

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

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

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

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

می‌توانید با استفاده از مثالی که در زیر آمده است یا با 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() بستگی به موارد استفاده شما دارد. اگر می‌خواهید داده‌ها را تغییر دهید، جایگزین کنید یا از آن‌ها استفاده کنید، شما باید map() را انتخاب کنید، زیرا یک آرایه جدید را با داده‌های تبدیل‌شده برمی‌گرداند.

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

امیدواریم این مقاله تفاوت بین این دو متد را برای شما شفاف ساخته باشد.

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید