به عنوان دولوپر جاوااسکریپت همیشه با لیست ها و آرایه ها سروکار داریم. از آرایه برای دسته بندی کردن آبجکت ها، جستجو، مرتب سازی، شکستن رشته ها و ... استفاده می کنیم.
اگر بخواهیم روی تمامی مقادیر موجود در یک آرایه، منطقی را پیاده کنیم، می توانیم از حلقه for استفاده کنیم. مثال های زیر را درنظر بگیرید.
آرایه ای از اعداد صحیح دارید و قصد دارید میانگین این اعداد را حساب کنید.
const numbers = [10, 25, 32, 48, 15, 6];
لیستی از دانش آموزان با فرمت زیر دارید و قصد دارید به هر آبجکت کلید جدیدی برای سن محاسبه شده دانش آموز اضافه کنید.
const students = [ { name: "Ali Rafati", class: "A1", birth_year: 1995}, {name: "Reza Molaei", class: "A1", birth_year: 1994}, {name: "Sadegh Ahmadi", class: "A2", birth_year: 1996} ];
لیستی از اسامی کاربران دارید و می خواهید حرف اول تمامی آنها بزرگ نمایش داده شود.
const users = ['ali', 'reza', 'sara', 'mohammad']
در مثال های ذکر شده ما نیاز به پیمایش تمامی مقادیر موجود در لیست داریم، تا بتوانیم به نتیجه موردنظر برسیم. اما تنها گزینه موجود استفاده از حلقه for نیست. راه های جایگزین بهتری وجود دارد!
فرض کنید لیستی از آبجکت ها را دارید، که می خواهید مقدار جدیدی به همه آیتم های آن اضافه کنید (مثال افزودن سن دانش آموز براساس سال تولد) و یا لیستی از مقادیری دارید که می خواهید تغییری روی همه آن ها اعمال کنید (مثال بزرگ کردن حرف اول اسامی کاربران). در این گونه مسائل می توانید از متد map کمک بگیرید.
برای اینکه به خوبی متوجه مزایای متد map شوید، ابتدا مسئله را با استفاده از حلقه for حل می کنیم.
const studentsWithAge = []; const currentYear = new Date().getFullYear(); for (let index = 0; index < students.length; index++) { const age = currentYear - students[index].birth_year; studentsWithAge.push({ ...students[index], age }); }
در ابتدا یک آرایه جدید با نام studentsWithAge تعریف کرده ایم، که قرار است لیست دانش آموزان همراه با سن آن ها را در خود نگه دارد. با استفاده از for یک پیمایش کلی روی تمامی آبجکت های دانش آموزان داریم، سن دانش آموز را محاسبه کرده و به لیست جدید دانش آموزان اضافه می کنیم.
حل مسئله با استفاده از متد map به صورت زیر خواهد بود.
const currentYear = new Date().getFullYear(); const studentsWithAge = students.map(student => { const age = currentYear - student.birth_year; return { ...student, age }; });
کد نوشته شده کوتاه تر شده و خوانایی بالاتری نسبت به روش حل قبلی دارد.
متد map یک callback function دریافت می کند که شامل سه پارامتر است. پارامتر اول مقدار فعلی حلقه، پارامتر دوم ایندکس جاری حلقه و پارامتر سوم همان آرایه ای است که متد map روی آن فراخوانی شده است.
const newItems = items.map((item, index, array) => { return newItem; })
تابع ارسال شده به متد map روی تمامی آیتم های موجود در لیست اجرا می شود و باید یک آیتم جدید را به عنوان مقدار تغییریافته برگرداند. تمامی مقادیر ارسال شده نهایتا از متد map برگردانده شده و به متغیر مدنظر (در این تکه کد newItems) نسبت داده می شود.
مثال های دیگری از مسائل حل شده با map
const numbers = [1, 2, 3, 4]; const numbersPowerTwo = numbers.map(number => Math.pow(number, 2)); console.log(numbers); //[1,2,3,4] console.log(numbersPowerTwo); //[1,4,9,16]
نکات موجود در تکه کد بالا
const users = ["ali", "reza", "sara", "mohammad"]; const capitalUsers = users.map(user => firstCharToUpper(user));
فرض کنید قصد داریم لیستی را براساس شرطی فیلتر کنیم و تنها آیتم هایی از لیست را در خروجی داشته باشیم که در شرط موردنظر صدق می کنند.
در این مثال هم ابتدا با for مسئله را حل می کنیم.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; const oddNumbers = []; for (let index = 0; index < numbers.length; index++) { if (numbers[index] % 2 !== 0) { oddNumbers.push(numbers[index]); } }
مانند مثال قبلی حل شده با for ابتدا یک آرایه جدید برای اعداد فرد در نظر می گیریم، در حلقه تعریف شده با یک شرط تعیین می کنیم که چه اعدادی می توانند به آرایه جدید اضافه شوند.
حل مسئله با استفاده از filter به صورت زیر خواهد بود.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; const oddNumbers = numbers.filter(function(number) { return number % 2 !== 0; });
این متد هم مانند map یک تابع callback دریافت می کند که شامل 3 پارامتر است، پارامتر اول مقدار فعلی حلقه، پارامتر دوم ایندکس فعلی و پارامتر سوم آرایه ای است که متد filter روی آن اعمال شده است.
const filteredItems = items.filter((item, index, array) => { return true / false; });
همانطور که می بینید مقدار بازگشتی تابع کال بک یک مقدار Boolean (شرطی) است. متد filter این شرط را روی تمامی آیتم های آرایه بررسی می کند، اگر true برگردانده شود مقدار فعلی به خروجی نهایی ارسال می شود، در غیر این صورت آن مقدار نادیده گرفته می شود.
const filteredStudents = students.filter(student => students.birth_year > 1995);
نکات موجود در تکه کد بالا
const strings = ["hello", "come in", "interface", "income", "at school"]; const stringsWithIn = strings.filter(str => str.includes("in"));
1. متدهای map و filter را می توان پشت سر هم و زنجیره وار اجرا کرد.
مثال: در آرایه ای که از دانش آموزان داشتیم، می خواهیم کاربرانی را نمایش دهیم که بیش از 25 سال سن دارند.
برای حل این مسئله ابتدا باید کلید جدیدی به نام age به هر آبجکت اضافه کنیم (متد map)، سپس با استفاده از متد filter روی مقدار age شرط بگذاریم.
const currentYear = new Date().getFullYear(); const filteredStudents = students .map(student => { const age = currentYear - student.birth_year; return { ...student, age }; }) .filter(student => student.age > 25);
2. با استفاده از متدهای map و filter به مقدار فعلی در هر پیمایش دسترسی داریم و نیازی نداریم با استفاده از ایندکس و آرایه به آن برسیم.
3. لیستی که متدهای map و filter روی آن فراخوانی شده اند، بدون تغییر باقی می ماند.
4. دردسر ایجاد یک آرایه جدید و push کردن و ... دیگر وجود ندارد.