در این درس میخوانید
فهرست درسها، نتیجهٔ جستوجو و اقلام سبد خرید، همگی نمونهٔ مجموعهٔ دادهاند. آرایه یک فهرست مرتب است که به هر عضو با ایندکس دسترسی میدهد. ایندکس نخست صفر است و length تعداد خانههای آرایه را نشان میدهد. در این درس هفتم، پیش از انتخاب متد میپرسیم خروجی چه شکلی باید باشد: آرایهٔ تازه، یک عضو، یا یک عدد؟ همین پرسش، انتخاب بین map و filter و reduce را روشن میکند.
دسترسی، افزودن و پیمایش
const lessons = ["متغیر", "تابع", "آرایه"];
console.log(lessons[0]); // متغیر
console.log(lessons.length); // 3
lessons.push("شیء");
console.log(lessons.at(-1)); // شیء
for (const lesson of lessons) console.log(lesson);push آرایهٔ اصلی را تغییر میدهد و طول تازه را برمیگرداند؛ نتیجهٔ آن خود آرایه نیست. const بودن lessons جلوی تغییر اعضا را نمیگیرد. اگر به ایندکس بیرون محدوده مراجعه کنید، معمولاً undefined میگیرید. همچنین حذف با delete طول آرایه را کم نمیکند و میتواند خانهٔ خالی بسازد؛ برای حذف منطقی یک عضو از فهرست، filter یا روش مناسب دیگری انتخاب کنید. آرایهٔ دارای حفره با فهرست معمولی و پُر یکسان رفتار نمیکند.
map برای تبدیل، filter برای انتخاب
map برای هر عضو یک نتیجه تولید میکند و آرایهٔ حاصل را برمیگرداند. filter فقط عضوهایی را نگه میدارد که شرط انتخاب را میگذرانند. اگر صرفاً کار جانبی مانند چاپ لازم دارید، for...of یا forEach میتواند روشنتر باشد؛ map را فقط برای اجرای یک کار جانبی و کنارگذاشتن خروجی به کار نبرید. تابع callback باید خروجی مورد انتظار را برگرداند؛ فراموشی return در بدنهٔ دارای آکولاد، آرایهای از undefined میسازد.
const scores = [8, 12, 17, 20];
const passed = scores.filter(score => score >= 10);
const labels = passed.map(score => `نمره: ${score}`);
console.log(passed); // [12, 17, 20]
console.log(labels); // ["نمره: 12", "نمره: 17", "نمره: 20"]
console.log(scores); // آرایهٔ اصلی حفظ شده است.find و some؛ پاسخِ مورد نیاز را بگیرید
find اولین عضو مطابق شرط را برمیگرداند و در نبود نتیجه، undefined میدهد. some بررسی میکند حداقل یک عضو شرط را دارد یا نه. every برای بررسی همهٔ عضوهاست؛ دربارهٔ آرایهٔ خالی، every برابر true و some برابر false میشود. اگر شرط کسبوکار شما وجود حداقل یک عضو است، طول فهرست را نیز بررسی کنید. جستوجوی موفق را تنها با if(found) تشخیص ندهید وقتی مقدار صفر میتواند نتیجهٔ معتبر باشد.
const values = [0, 4, 9];
const found = values.find(value => value === 0);
console.log(found !== undefined); // true
console.log(values.some(value => value > 8)); // true
console.log(values.every(value => value >= 0)); // truereduce برای تبدیل چند مقدار به یک نتیجه
const minutes = [20, 15, 30];
const totalMinutes = minutes.reduce((sum, value) => sum + value, 0);
console.log(totalMinutes); // 65
console.log([].reduce((sum, value) => sum + value, 0)); // 0در این مثال، accumulator همان sum است و در هر دور با مقدار جدید ترکیب میشود. مقدار اولیهٔ صفر هم قرارداد را روشن میکند و هم آرایهٔ خالی را پوشش میدهد. بدون مقدار اولیه، reduce در فهرست خالی خطا میدهد. اگر تابع reduce برای همکارتان دشوار شده، یک حلقهٔ ساده ممکن است خواناتر باشد؛ استفاده از متد پیشرفته بهتنهایی کیفیت کد را بالاتر نمیبرد. معیار، روشنبودن منطق و رفتار در حالتهای مرزی است.
مرتبسازی عددی و حفظ ورودی
sort آرایهٔ اصلی را تغییر میدهد و بدون comparator، مرتبسازی بر پایهٔ نمایش رشتهای انجام میشود؛ بنابراین برای عددها تابع مقایسه لازم است. toSorted یک آرایهٔ مرتبشدهٔ تازه میسازد و در محیطهای بهروز در دسترس است. برای محیط قدیمیتر میتوانید ابتدا با spread کپی بگیرید و سپس sort کنید. این کپی سطحی است: اگر عضوها شیء باشند، شیءهای تودرتو هنوز میتوانند مشترک بمانند.
const prices = [100, 20, 3];
const ascending = prices.toSorted((a, b) => a - b);
// جایگزین سازگارتر: [...prices].sort((a, b) => a - b)
console.log(ascending); // [3, 20, 100]
console.log(prices); // [100, 20, 3]تمرین: جمع اقلام قابل خرید
دو قلم کالا داریم و فقط عضوهای فعال باید وارد جمع شوند. هر عضو یک شیء با قیمت، تعداد و وضعیت است؛ ساختار شیء را در درس بعد کامل میخوانیم. مبلغ هر سطر برابر price ضرب در quantity است. برای دادهٔ زیر، خروجی باید 80000 باشد. ابتدا با filter عضوهای فعال را انتخاب کنید و بعد reduce را با صفر اولیه به کار ببرید. در دادهٔ واقعی، معتبر بودن قیمت و تعداد باید پیش از این محاسبه تضمین شود.
const cart = [
{ title: "کتاب", price: 40000, quantity: 2, active: true },
{ title: "دفتر", price: 15000, quantity: 1, active: false }
];
const payable = cart.filter(item => item.active)
.reduce((sum, item) => sum + item.price * item.quantity, 0);
console.log(payable); // 80000اشتباههای رایج و سؤال مرور
- انتظار آرایه از push، در حالی که مقدار بازگشتی آن طول تازه است.
- استفاده از map بدون نیاز به آرایهٔ خروجی.
- مرتبسازی عددها بدون comparator.
- فراموشکردن مقدار اولیهٔ reduce و حالت فهرست خالی.
- فرض اینکه spread یک کپی عمیق از تمام اعضا میسازد.
برای مرور، توضیح دهید چرا خروجی find ممکن است صفر باشد، چرا sort میتواند دادهٔ اصلی را تغییر دهد و برای نمایش عنوان همهٔ درسها کدام متد را انتخاب میکنید. سپس تمرین را با سبد خالی و با دو قلم فعال اجرا کنید. نتیجهٔ درست برای یک ورودی کافی نیست؛ قرارداد رفتار در نبود داده را هم روشن کنید.
منابع انگلیسی
- MDN — Array
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
- MDN — Array.prototype.map
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
- MDN — Array.prototype.reduce
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
مثالهای فارسی و سبد خرید برای این مجموعه طراحی شدهاند. در درس بعد، شیءها، destructuring و بهروزرسانی دادهٔ تودرتو را بررسی میکنیم.
پیشنیاز و محیط اجرای مثالها
درس 7 از ۲۰؛ پیشنیاز: درسهای قبلی مجموعه. کدهای مستقل این درس در Console تازهٔ مرورگر یا فایل JavaScript اجرا میشوند؛ نمونهها را جداگانه آزمایش کنید.
پیشرفت روی همین مرورگر ذخیره میشود.