مقدمه کوتاه بر توابع سطح بالا در جاوا اسکریپت
تابعی که توابع دیگر را به عنوان آرگومان می پذیرد و یا به عنوان مقدار بازگشتی باز می گرداند تابع سطح بالا نامیده میشود. این توابع سطح بالا نامیده می شوند زیرا به جای انجام عملیات بر روی رشته ها، اعداد و مقادیر منطقی فراتر از اینها بر روی توابع اعمال می شوند.
با استفاده از توابع در جاوا اسکریپ شما می توانید : آنها را همچون متغیر ذخیره سازی کنید. از آنها در آرایه ها استفاده کنید و به آنها همچون پروپرتی های اشیا انتساب دهید. آنها را همچون آرگومان ها ارسال کنید و آنها را از تابعی دیگر بازگشت دهید. در واقع می توان با توابع در جاوا اسکریپ همچون دادههای دیگر رفتار کرد. این ویژگی میتواند بسیار کلیدی و مفید باشد.
توابعی که بر روی این داده ها اعمال می شوند
رشته ها نوعی داده هستند :
sayHi = (name) => `Hi, ${name}!`;
result = sayHi('User');
console.log(result); // 'Hi, User!'
اعداد نوعی داده هستند :
double = (x) => x * 2;
result = double(4);
console.log(result); // 8
مقادیر بولین نوعی داده هستند :
getClearance = (allowed) => allowed ?
'Access granted' :
'Access denied';
result1 = getClearance(true);
result2 = getClearance(false);
console.log(result1); // 'Access granted'
console.log(result2); // 'Access denied'
اشیا نوعی داده هستند :
getFirstName = (obj) => obj.firstName;
result = getFirstName({
firstName: 'Yazeed'
});
console.log(result); // 'Yazeed'
آرایه ها نوعی داده هستند :
len = (array) => array.length;
result = len([1, 2, 3]);
console.log(result); // 3
پنج نوع داده ای که در بالا نام برده شد، انواع داده ای اصلی درجه اول در هر زبانی هستند. چه چیزی باعث شده است آنها درجه اول باشند؟ شما میتوانید آنها را به هر جایی ارسال و آنها را در متغیر ها و آرایه ها ذخیره سازی کنید. از آنها میتوانید به عنوان ورودی برای محاسبات استفاده کنید. در واقع می توان از آنها مانند هر نوع داده دیگری استفاده نمود.
توابع نیز نوعی داده محسوب می شوند
در مثال زیر از یک تابع به عنوان آرگومان استفاده کرده ایم :
isEven = (num) => num % 2 === 0;
result = [1, 2, 3, 4].filter(isEven);
console.log(result); // [2, 4]
ببینید که چطور filter از isEven برای انتخاب اعداد استفاده میکند؟ isEven یک تابع بوده که به عنوان آرگومان برای تابعی دیگر فرستاده شده است. این تابع به ازای هر عدد به وسیله تابع filter فراخوانی میشود و از مقدار true و false برای تعیین زوج و فرد بودن اعداد استفاده می کند.
بازگشت توابع
add = (x) => (y) => x + y;
add به دو پارامتر نیاز دارد، اما نه به هر دوی آنها در یک بار. تابع add تابعی است که ابتدا به پارامتر x نیاز دارد که این پارامتر خود پارامتر y را در قالب یک تابع برمیگرداند. این قابلیت تنها در جاوا اسکریپت در دسترس است، زیرا جاوا اسکریپت به توابع اجازه میدهد به عنوان یک مقدار return شوند(درست مانند رشته ها، اعداد، مقادیر بولین و غیره).
شما همچنین می توانید مقادیر x و y را سریعاً فراهم کنید. این کار به شکل زیر می تواند انجام شود :
result = add(10)(20);
console.log(result); // 30
و یا ابتدا پارامتر x را فراهم آورده، سپس پارامتر y را ارسال کنید :
add10 = add(10);
result = add10(20);
console.log(result); // 30
بگذارید به مثال اخیر نگاهی بیندازیم. add10 نتیجه فراخوانی تابع add با یک پارامتر است. سعی کنید آن را در پنجرخ کنسول مرورگر به شکل زیر وارد کنید :
add10 یک تابع است که مقدار y را دریافت نموده و نتیجه x + y را برمیگرداند. بعد از فراهم آوردن پارامتر y به سرعت نتیجه محاسبه شده و به عنوان نتیجه نهایی بازگشتخواهد شد.
قابلیت استفاده مجدد بیشتر
احتمالاً بزرگترین مزیت HOFها(توابع سطح بالا) قابلیت استفاده مجدد بیشتر است. بدون استفاده از آنها ، متدهای آرایه ای همچون map ، filter و reduce
وجود نخواهد داشت.
در زیر لیستی از کاربران را داریم. می خواهیم محاسباتی را بر اساس اطلاعات آنها انجام دهیم :
users = [{
name: 'Yazeed',
age: 25
}, {
name: 'Sam',
age: 30
}, {
name: 'Bill',
age: 20
}];
Map
بدون توابع سطح بالا ما مجبور هستیم هر بار قابلیت Map را به صورت زیر پیاده سازی کنیم :
getName = (user) => user.name;
usernames = [];
for (let i = 0; i < users.length; i++) {
const name = getName(users[i]);
usernames.push(name);
}
console.log(usernames);
// ["Yazeed", "Sam", "Bill"]
اما اکنون با استفاده از تابع سطح بالای Map به صورت زیر این کار انجام می شود :
usernames = users.map(getName);
console.log(usernames);
// ["Yazeed", "Sam", "Bill"]
Filter
در دنیایی که توابع سطح بالا نقشی ندارند برای پیاده سازی تابع Filter نیاز به حلقه ها داریم :
startsWithB = (string) => string
.toLowerCase()
.startsWith('b');
namesStartingWithB = [];
for (let i = 0; i < users.length; i++) {
if (startsWithB(users[i].name)) {
namesStartingWithB.push(users[i]);
}
}
console.log(namesStartingWithB);
// [{ "name": "Bill", "age": 20 }]
اما این کار با استفاده از تابع سطح بالای Filter به آسانی به صورت زیر انجام میشود :
namesStartingWithB = users
.filter((user) => startsWithB(user.name));
console.log(namesStartingWithB);
// [{ "name": "Bill", "age": 20 }]
Reduce
تابع سطح بالای بعدی Reduce است که بدون قابلیت توابع سطح بالا به شکل زیر پیاده سازی می شود :
total = 0;
for (let i = 0; i < users.length; i++) {
total += users[i].age;
}
console.log(total);
// 75
و اکنون با استفاده از توابع سطح بالا :
totalAge = users
.reduce((total, user) => user.age + total, 0);
console.log(totalAge);
// 75
نتیجه گیری
رشته ها، اعداد، مقادیر بولین و اشیا میتوانند در متغیر ها، آرایه ها و پروپرتی های متدها ذخیره سازی شوند. جاوااسکریپت با توابع نیز به همین شکل رفتار میکند. این کار به توابع اجازه میدهد بر روی دیگر توابع عملیات مورد نظر خود را انجام دهند. به این توابع، توابع سطح بالا گفته میشود. توابع سطح بالا Map ، filter و reduce مثالی از توابع سطح بالا هستند که کار ما را بسیار ساده تر می کنند.