گام به گام با ES6 – آرایه
در ادامهی بررسی بخشهای مختلف ES6 در این مقاله به سراغ آرایهها میرویم. طبق سیاستهایی که پیشتر هم در ES6 دیدیم همانطور که انتظار میرود قابلیتهای جدید ارائه شده برای کار با آرایهها نیز در جهت کمتر شدن کدهای نوشته شده و کمتر شدن خطا قرار دارند. با ما همراه باشید تا برخی از این قابلیتها را بررسی کنیم.
ForEach
با استفاده از forEach میتوانیم آرایه را بدون در نظر گرفتن index و به شکلی ساده پیمایش کنیم. مثال زیر را ببینید:
var cars = [ 'Lamborghini', 'Bugatti', 'Aston Martin' ]; // ES5 for (var i = 0; i < cars.length; i++) { console.log(cars[i]); }; // ES6 cars.forEach(function(car) { console.log(car); });
برای استفاده از forEach، یک تابع به عنوان آرگومان به آن میدهیم . به ازای هر خانهای که در آرایه وجود دارد یکبار این تابع اجرا میشود. این تابع آرگومانی نیز دریافت میکند که محتویات همین خانه در آن قرار دارد. اصطلاحا به این تابع، تابع تکرار(iterator function) میگویند.
در مثال بالا به ازای هر خانهی آرایهی cars، یکبار تابعی که نوشته شده اجرا میشود و محتویات این خانه توسط آرگومان car قابل دسترس است.
map
قابلیت دیگری که از این به بعد هنگام استفاده از آرایهها در اختیار داریم، قابلیت map کردن است. map یکی از ویژگیهای بسیار کاربردی است که جای خالی آن به شدت احساس میشد. مثال زیر را ببینید تا با چگونگی استفاده از این قابلیت در جاوااسکریپت آشنا شوید:
var cars = [ 'Lamborghini', 'Bugatti', 'Aston Martin' ]; // ES5 var carList = []; for (var i = 0; i < cars.length; i++) { carList.push({brand: cars[i]}); } // ES6 var carList = cars.map(function(car) { return {brand: car}; }); // output => [{brand: 'Lamborghini'}, ...]
در مثال بالا فرض کنید لیستی از اتومبیلها را داریم ولی برای فرستادن این لیست برای کاربر میخواهیم که هر خانهی این آرایه به شکل objectی دارای کلید name باشد. برای این کار، مشابه forEach یک تابع تکرار به عنوان آرگومان به map میدهیم.
تفاوتی که map با forEach دارد در این است که وقتی از forEach استفاده میکنیم، نمیخواهیم آرایه را به شکل دیگری دربیاوریم و فقط میخواهیم از آرایهی موجود استفاده کنیم؛ ولی در map تصمیم داریم تا با تغییر در ساختار این آرایه، آرایهی دیگری بهوجود بیاوریم. پس با این توضیحات نتیجه میگیریم که در map نیاز داریم تا خروجی داشته باشیم. همین قضیه باعث میشود تا دو تغییر در ساختار map نسبت به forEach ببینیم. اول اینکه cars.map خروجی دارد و این خروجی را در آرایهای ذخیره میکنیم(خط ۱۴). دوم اینکه برای بودن خانههای آرایه در آرایهی جدید، تابع تکراری که نوشتیم باید ساختار خانهی جدید را return کند. در مثال بالا هر بار که تابع تکرار خانهای از آرایه را دریافت میکند، مقدار آن را در objectی قرار میدهد و این object را return میکند. این مقدار return شده به انتهای آرایهی جدید اضافه میشود.
find
find همانطور که از اسمش پیداست زمانی استفاده میشود که میخواهیم ببینیم عنصر مورد نظر در آرایه وجود دارد یا نه.
var cars = [ {name: 'm4', color: 'gold'}, {name: 'Azera', color: 'white'}, {name: 'Optima', color: 'black'} ]; // ES5 var car; for (var i = 0; i < cars.length; i++) { if (cars[i].color == 'gold') { car = cars[i]; break; } } console.log(car); // ES6 var car = cars.find(function(car) { if (car.color == 'gold') { return true; } }); console.log(car);
find هم مثل بقیه helperهایی که معرفی کردیم یک تابع تکرار میگیرد. در این تابع چک میکنیم که اگر عنصر مورد نظر ما وجود داشت true را return کنیم. find وقتی خروجی true دریافت کرد، خانهای از آرایه که در حال کار بر روی آن هستیم(خانهی جاری، خانهای که عنصر مورد نظر در آن وجود داشت) را به عنوان خروجی برمیگرداند و بقیه خانههای آرایه را بررسی نمیکند.
filter
از filter زمانهایی استفاده میکنیم که نیاز داریم تا فقط بخشی از آرایه را نمایش دهیم. برای مثال فقط میخواهیم اتومبیلهایی که رنگ سفید آنها موجود هست را نمایش دهیم. مثال زیر همین کار را انجام میدهد:
var cars = [ {name: 'm4', color: 'gold'}, {name: 'Azera', color: 'white'}, {name: 'Optima', color: 'white'} ]; // ES5 var carList = []; for (var i = 0; i < cars.length; i++) { if (cars[i].color == 'white') { carList.push(cars[i]); } } console.log(carList); // ES6 var carList = cars.filter(function(car) { if (car.color == 'white') { return true; } }); console.log(carList);
فرق filter با find در این است که find بعد از پیدا کردن عنصر مورد نظر، بقیه خانههای آرایه را نادیده میگیرد ولی filter تمام خانههای آرایه را میگردد و تمام خانههایی که با شرط ما همخوانی دارند را به عنوان خروجی برمیگرداند.
every & some
از every برای این استفاده میشود که ببینم “آیا تمام خانههای آرایه دارای عنصر مورد نظر هستند؟”؛ و از some بدین منظور استفاده میشود که ببینیم “آیا خانهای در آرایه پیدا میشود که عنصر مورد نظر را داشته باشد؟”.
مثال زیر را برای every ببینید:
var cars = [ {name: 'm4', country: 'Germany'}, {name: 'Azera', country: 'Korea'}, {name: 'Optima', country: 'Korea'} ]; // ES5 var is = true; for (var i = 0; i < cars.length; i++) { if (cars[i].country !== 'Germany') { is = false; break; } } console.log(is); // false // ES6 var is = cars.every(function(car) { if (car.country == 'Germany') { return true; } }); console.log(is); // false
متغیر is زمانی مقدار true میگیرد که مقدار country تمام خانههای آرایه برابر ‘Germany’ باشد. یعنی تمام اتومبیلها برای آلمان باشند.
مثال زیر را برای some ببینید:
var cars = [ {name: 'm4', country: 'Germany'}, {name: 'Azera', country: 'Korea'}, {name: 'Optima', country: 'Korea'} ]; // ES5 var is = false; for (var i = 0; i < cars.length; i++) { if (cars[i].country == 'Germany') { is = true; break; } } console.log(is); // true // ES6 var is = cars.some(function(car) { if (car.country == 'Germany') { return true; } }); console.log(is); // true
متغیر is زمانی مقدار true میگیرد که مقدار country حداقل یکی از خانههای آرایه برابر ‘Germany’ باشد. یعنی حداقل یک اتومبیلها برای آلمان باشد.
reduce
از تابع reduce میتوانیم زمانهایی مثل وقتی که میخواهیم جمع اعدادی در آرایه را به دست آوریم استفاده کنیم. مثال زیر را ببینید:
var cars = [ {name: 'm4', price: 60000}, {name: 'Azera', price: 30000}, {name: 'Optima', price: 20000} ]; // ES5 var sum = 0; for (var i = 0; i < cars.length; i++) { sum += cars[i].price; } console.log(sum); // ES6 var sum = cars.reduce(function(s, car) { return s + car.price; }, 0); console.log(sum);
reduce دو آرگومان دریافت میکند. آرگومان اول همان تابع تکرار است، آرگومان دوم مقدار اولیه خروجی است. تابع تکرار هم دو آرگومان دریافت میکند. آرگومان اول خروجی مرحلهی قبل است(که مقدار اولیه آن در آرگومان دوم reduce مشخص میشود) و آرگومان دوم خانهای از آرایه که در آن قرار داریم.
در مثال بالا مقدار اولیهی s برابر ۰ است. هر بار که تابع تکرار اجرا میشود مقدار price خانهی جاری را با s جمع میکند و return میکند. مرحلهی بعد این مقدار را به عنوان آرگومان اول دریافت میکند. در نهایت هرچه از reduce بازگشت داده شد در sum میریزیم و نمایش میدهیم.
نکتهای که باید توجه کنید این است که این array helperها اگرچه کار را برای ما خیلی آسانتر کردند و استفاده از آنها خوانایی کد ما را نیز افزایش میدهد ولی از نظر performance چند قدم عقبتر از حلقهی for عادی هستند. این تفاوت در مرورگرهای امروزی به چشم نمیآید؛ ولی اگر برنامهای مینویسید که منابع سیستمی نقش حیاتیتری دارند پیشنهاد میشود از حلقهی for استفاده کنید تا کد بهینهتری داشته باشید.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.