۶ متد آرایه جاوا اسکریپت برای کدنویسی بهینه‌تر — راهنمای کاربردی

۲۶۲ بازدید
آخرین به‌روزرسانی: ۰۸ شهریور ۱۴۰۲
زمان مطالعه: ۷ دقیقه
۶ متد آرایه جاوا اسکریپت برای کدنویسی بهینه‌تر — راهنمای کاربردی

باید توجه داشته باشید که در حوزه برنامه‌نویسی همه چیز در شیءگرایی خلاصه نشده است. زمانی که از «برنامه‌نویسی تابعی» (functional programming) صحبت می‌کنیم، در واقع بیشتر با پردازش‌هایی سر و کار داریم که شما را از نقطه الف به نقطه ب می‌برند، تا این که بخواهیم بدانیم داده‌ها و گروه‌های مختلف منطق تجاری چگونه سازمان‌دهی شده‌اند. در این مقاله به بررسی انواع متد آرایه جاوا اسکریپت می‌پردازیم.

جاوا اسکریپت زبانی است که مستعد نفوذ الگوهای دستوری (imperative) است، چون انتخاب این روش آسان است. توسعه‌دهندگان زیادی میل دارند که کدشان را به روش «رویه‌ای» (procedural) بنویسند. در این روش یک مشکل در رویه می‌تواند موجب از کار افتادن کد و یا ایجاد باگ‌های جانبی شود. به همین دلیل است که الگوهای تابعی مطرح شده‌اند.

مروری بر مبانی برنامه‌نویسی تابعی

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

به مدل رویه‌ای زیر توجه کنید:

Start.
Check computer power status
if on, proceed to next step. Else proceed to turn computer on.
Enter password. If password accepted, proceed. Else try again.
Open browser.
Start browsing the Internet.
End.

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

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

در جاوا اسکریپت در اغلب موارد با آرایه‌ها کار می‌کنیم، اما توسعه‌دهندگان زیادی وجود دارند که میل دارند در صورت عدم ضرورت از الگوی دستوری استفاده کنند. حلقه‌های while و for می‌توانند برای فیلتر کردن، یافتن یا انجام کاری روی هر مقدار درون آرایه استفاده شوند.

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

()filter() ،find() ،map() ،reduce() ،every و ()some شش متد آرایه‌ای در جاوا اسکریپت هستند که برای جلوگیری از بروز چنین مشکلاتی به فراوانی مورد استفاده قرار گیرند. استفاده از این متدها در کد جالب است زیرا برای عملکرد خود نیازی به وجود یک حالت (State) ندارند.

شیوه استفاده از ()filter

()filter متدی است که امکان ایجاد یک آرایه جدید بر مبنای شرایطی که از روی یک آرایه موجود به صورت true ارزیابی شده است را فراهم می‌سازد. به مثال زیر توجه کنید:

1let animals = [
2   {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2},
3   {name: 'Fluffball', type: 'rabbit', isNeutered: false, age: 1},
4   {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
5 ]
6
7 /*using imperative*/
8 let neuteredAnimals = [];
9
10for (let i=0; i < animals.length; i++){
11  let a = animals[i];
12  if(a.isNeutered){
13    neuteredAnimals.push(a);
14  }
15}

مثال فوق یک الگوی رویه‌ای دارد که غالباً به عنوان روشی برای تعریف حلقه روی هر آیتم در آرایه، تست شرط و سپس ارسال آن به آرایه می‌بینیم.

با استفاده از متد ()filter کافی است شرط را تعیین کنید:

1let animals = [
2    {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2},
3    {name: 'Fluffball', type: 'rabbit', isNeutered: false, age: 1},
4    {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
5  ]
6
7 /*using functional filter() where a represents an item in the array*/
8 let neuteredAnimals = animals.filter((a) => {
9     return a.isNeutered;
10 });

در کد فوق باید متد فیلتر را روی یک آرایه تنظیم کنیم. تابع بی‌نام اجازه می‌دهد که a نماینده یک آیتم منفرد در آرایه باشد که به همان روش a = animals[i]‎ در الگوی رویه‌ای عمل می‌کند. هر چیزی که از ()filter بازگشت یابد آن را در آرایه جدید قرار می‌دهیم.

شیوه استفاده از ()find

()find در جاوا اسکریپت برای ایجاد یک شیء جدید بر مبنای شرط تعیین‌شده استفاده می‌شود. در ظاهر شبیه به ()filter است، اما در باطن چنین نیست. ()filter یک آرایه از اشیای مطابقت یافته بازگشت می‌دهد، در حالی که ()find نخستین شیء مطابقت یافته را بازمی‌گرداند. به مثال زیر توجه کنید:

1let animals = [
2    {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2},
3    {name: 'Fluffball', type: 'rabbit', isNeutered: false, age: 1},
4    {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
5  ]
6
7animalTypeFound = animals.find( animal => animal.type === 'cat' );
8
9// animalTypeFound will return:
10// {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2}
11
12animalTypeFilter = animals.filter( animal => animal.type === 'cat' );
13
14// animalTypeFilter will return:
15// [{name: 'Tibbers', type: 'cat', isNeutered: true, age: 2}, {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}]

()find در نخستین مورد مطابقت یافته می‌ایستد، در حالی که ()filter ادامه می‌دهد تا این که همه آیتم‌های مطابقت بافته در آرایه را بازگشت دهد.

شیوه استفاده از ()map

فرض کنید آرایه‌ای دارید اما می‌خواهید متفاوت به نظر برسد. می‌توانید با استفاده از تابع ()forEach روی آن حلقه‌ای تعریف کنید، اما این امر در ادامه موجب بروز پیچیدگی‌هایی می‌شود.

نگاشت کردن یا استفاده از map به شما امکان می‌دهد که با مقادیر کار کنید، آن‌ها را به سلکتورهای متفاوتی بازطراحی کنید و هر کار دیگری که دوست دارید روی آن‌ها اجرا نمایید. نتیجه ()map یک شیء است که امکان ذخیره جفت‌های کلید/مقدار یا صرفاً یک آرایه از مقادیر ساده را می‌دهد. به مثال زیر توجه کنید تا ساختار آن را دریابید:

1let animals = [
2    {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2},
3    {name: 'Fluffball', type: 'rabbit', isNeutered: false, age: 1},
4    {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
5  ]
6
7// what you need: 
8// ['Tibbers', 'Fluffball', 'Strawhat']
9
10let animalNames = animals.map(animal => {return animal.name});
11
12// what you need: 
13// [{name: 'Tibbers', species: 'cat'}, {name: 'Fluffball', species: 'rabbit'}, {name: 'Strawhat', species: 'cat'}]
14
15let petDetails = animals.map(animal => {
16    return {
17        name: animal.name, 
18        species: animal.type
19    };
20});

شیوه استفاده از ()reduce

گهگاه خبرهایی در مورد reduce می‌شنویم، اما هیچ کس دقیقاً نمی‌داند که دقیقاً چه کار می‌کند. به طور خلاصه ()reduce امکان تعامل یافتن دو مقدار یا شیء را که از سمت چپ به راست مجاور هم هستند فراهم می‌سازد.

برای نمونه فرض کنید آرایه‌ای به صورت [100 ,20 ,10]‎‎ دارید. اگر بخواهید از ()reduce روی آن استفاده کنید، نخستین مجموعه از مقادیر 100 و 20 خواهند بود. سپس خروجی آن هر چه باشد برای تعامل با 10 استفاده می‌شود.

1let numbers = [100, 20, 10];
2
3// result will return 70 as the value
4// The function inside reduce will run twice. 
5// the first time, x = 100, y = 20
6// the second time, x = 80, y = 10
7
8result = numbers.reduce((x, y) => { return x - y; });

()reduce می‌تواند دو آرگومان نیز بگیرد. آرگومان نخست تابعی است که تعیین می‌کند بر سر دو مقدار نخست چه آمده است و تابع دوم مقدار آغازین را تعیین می‌کند.

1let animals = [
2    {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2},
3    {name: 'Fluffball', type: 'rabbit', isNeutered: false, age: 1},
4    {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
5  ]
6
7// How old are all the animals combined?
8// 0 is the starting value and acts as the first acculmulator value
9// will return 8
10
11let totalAge = animals.reduce((acculmulator, animal) => {
12    return acculmulator + animal.age;
13}, 0);
14
15// lets say you want to find out the oldest animal 
16// code below will return {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
17
18let oldestPet = animals.reduce((oldest, animal) => {
19    return (oldest.age || 0) > animal.age ? oldest : animal;
20  }, {});
21
22  // decrypting the code above and how terniaries work 
23  // the condition --> (oldest.age || 0) > animal.age 
24  // if true --> ? oldest
25  // else --> : animal

شیوه استفاده از ()every

متد every بر اساس شرط تعیین شده یک مقدار true یا false بازگشت می‌دهد. طرز کار آن شبیه به ()filter است اما به جای بازگشت یک شیء یا مقدار، این متد یک مقدار بولی بازگشت می‌دهد:

1let animals = [
2    {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2},
3    {name: 'Fluffball', type: 'rabbit', isNeutered: false, age: 1},
4    {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
5  ]
6
7let allNeutered = animals.every(animal => {return animal.isNeutered});
8
9//will return false because not all values under isNeutered evaluates to true

بدین ترتیب ()every به گزینه‌ای مناسب برای بررسی این نکته تبدیل شده است که آیا همه چیز درون یک آرایه معیار تعیین شده را دارد یا نه.

شیوه استفاده از ()some

طرز کار ()some مشابه ()every است، اما تنها یک شرط باید true ارزیابی شود تا نتیجه درست باشد. به مثال زیر توجه کنید:

1let animals = [
2    {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2},
3    {name: 'Fluffball', type: 'rabbit', isNeutered: false, age: 1},
4    {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
5  ]
6
7let someAreCats = animals.some(animal => {return animal.type === 'cat'});
8
9// will return true because at least one animal.type returned 'cat'

در کاربردهای واقعی باید از ()every و ()some برای بررسی مقادیر درون آرایه پیش از ارسال آن‌ها به پایگاه داده استفاده کنید.

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

ترکیب متدها

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

1let animals = [
2    {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2, enteredPagent: true, cutenessScore: 347},
3    {name: 'Fluffball', type: 'rabbit', isNeutered: false, age: 1, enteredPagent: true, cutenessScore: 193},
4    {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5, enteredPagent: false, cutenessScore: 521}
5  ]
6
7//lets say you want to find the total cuteness score of all valid pagent entrants
8
9let totalScore = animals
10                    .filter(animal => {return animal.isNeutered})
11                    .reduce((accumulator, animal) => {return accumulator + animal.cutenessScore}, 0);
12
13// totalScore will return 868

بسته به مجموعه داده‌ها می‌توانید کارهای کاملاً مؤثری روی آرایه اجرا کنید و نیاز به تعریف دستی حلقه روی همه آرایه‌ها و الزام آن‌ها به انجام کارهای مورد نظر را کاهش دهید.

سخن پایانی

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

با این حال این الگوها زمانی که با بیش از یک حلقه for یا while سر و کار داشته باشید، به سرعت به کلاف درهم‌ پیچیده‌ای تبدیل می‌شوند. متدهای آرایه‌ای از بسیاری از اشتباهات که خاصیت کدهای طولانی هستند، براکت های تو در تو و نقطه‌ویرگول‌های فراموش‌شده جلوگیری می‌کنند.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۳ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
better-programming
۳ دیدگاه برای «۶ متد آرایه جاوا اسکریپت برای کدنویسی بهینه‌تر — راهنمای کاربردی»

سلام مقاله بسیار خوبی بود ممنون بابت ترجمه بسیار خوبی که داشتید.
فقط یک بخش از کد ها رو جا انداختین و برای همین کد مربوط به ترکیب متدها رو نذاشتین !

سلام امیر عزیز؛
مشکلی که فرمودید اصلاح شد.
ممنونیم از توجه شما و به داشتن خوانندگان دقیقی مثل شما افتخار می‌کنیم.

راهتمای خیلی عالی بود.

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *