arrow function ها در جاوا اسکریپت پر کاربرد و محبوب هستن چون سینتکس کوتاهی دارن، هنگام استفاده از اونها معنای this رو به خوبی میشه درک کرد و برای استفاده به عنوان call-back بسیار مناسبن.
حالا اجاره بدین با هم 5 اصل رو یاد بگیریم که کمک میکنه حتی فواید بیشتری از arrow function ها نصیبمون بشه.
1. نامگذاری arrow function ها
Arrow function ها در جاوا اسکریپت anonymous یا ناشناس هستن، به این معنی که اسمی ندارن یا در حقیقت اسم اونها یک رشته خالی " " هست.
در طول پروسه دیباگ کردن یک کد، این موضوع میتونه برای ما مشکل ساز باشه. به تصویر زیر نگاه کنید:
بخش call stack در سمت راست شامل دو تابع هست که هر دوی اونها anonymous هستن. در حال حاضر نمیتونیم هیچ اطلاعات مفیدی رو از این بخش بدست بیاریم. برای حل این مشکل بهتره هنگام تعریف arrow function ها، به اون ها نامی رو اختصاص بدیم. اما چطور چنین چیزی ممکنه؟
به سادگی با function name inference ! این قابلیتِ ES2015 میتونه اسم تابع رو در شرایطی خاص تشخیص بده. (برای مطالعه دیگر قابلیت ها و ترفندهای اکما اسکریپت 6 به مقاله آموزش 10 ترفند کاربردی در اکما اسکریپت 6 مراجعه کنید) ایده function inference اینه که جاوااسکریپت بتونه اسم arrow function رو از محل سینتکس اون تشخیص بده مثلا از متغیری که اون arrow function رو نگهداری میکنه. با یه مثال نشونتون میدم که function inference چطور کار میکنه:
const sayHello = userName => "Hello " + userName + ", welcome!";
sayHello.name; // => 'sayHello'
بخاطر اینکه متغیر sayHello تابع arrow function رو نگهداری میکنه، جاوااسکریپت تصمیم گرفته که “sayHello” میتونه اسم مناسبی برای arrow function باشه یا به عبارتی این رو به عنوان اسم تابع درک کرده؛ به همین دلیل arrow function این اسم رو تصاحب کرده و میتونیم با این اسم به اون دسترسی داشته باشیم.
یک best practice اینه که arrow function ها در جاوا اسکریپت رو با استفاده از این قابلیت (function name inference) نامگذاری کنیم.
حالا بیاین دوباره به یک عکس که مربوط به دیباگ کردن یک تکه کده نگاه کنیم با این تفاوت که این بار از name inference استفاده کردیم:
بخاطر اینکه توابع دارای نام هستن حالا call stack اطلاعات بیشتری درباره کد اجرا شده به ما میده.
handleButtonClick نشون میده که یک click event رخ داده و increaseCounter نشون میده که مقدار یک متغیر افزایش پیدا کرده.
2. استفاده از فرم کوتاه
یک تابع که به شکل مختصر و در صورت امکان تک خطی نوشته شده باشه، قابل فهم تر و خوندن اون آسون تره. تابع خطی یا inline function به تابعی گفته میشه که فقط یک عبارت (دستور) داره.
arrow function ها در جاوا اسکریپت این قابلیت رو دارن که به صورت فرم کوتاه نوشته بشن.
مثلا به جای استفاده از فرم طولانیِ کد زیر:
const array = [1, 2, 3];
array.map((number) => {
return number * 2;
});
بهتره از شکل مختصر اون استفاده کنیم، به این صورت که وقتی arrow function فقط یک دستور رو اجرا میکنه میتونیم برکت ها { } و دستور return رو حذف کنیم.
const array = [1, 2, 3];
array.map(number => number * 2);
3. استفاده از عملگرهای مقایسه ای در arrow function
علامتی که arrow function رو با اون تعریف میکنیم، fat arrow ( <= ) نام داره. این علامت بسیار شبیه به عملگرهای مقایسه ای (< , > , =< , =>) هست. وقتی این عملگر ها در یک inline arrow function استفاده میشن باعث گیج شدن هنگام خوندن کد میشن و احتمال بروز اشتباه رو زیاد میکنن. یک مثال میزنم:
const checkAge = age => age <= 10 ? "Oops! you can't use this device" : "let's go!";
وجود هر دو علامت => و <= در یک خط گمراه کنندهست.
برای حل این مشکل دو راه داریم؛ اول اینکه تمام عبارت محاسباتی رو داخل پرانتز قرار بدیم:
const checkAge = age => (age <= 10 ? "Oops! you can't use this device" : "let's go!");
دومین راه اینه که تابع رو به شکل کامل اون بنویسیم:
const checkAge = age => {
return age <= 10 ? "Oops! you can't use this device" : "let's go!";
};
این تغییرات باعث میشن تا امکان اشتباه کاهش و خوانایی کد افزایش پیدا کنه.
4.استفاده از object ها در arrow function
استفاده از objectها به شکل ساده درون inline arrow function باعث ایجاد ارور میشه:
const array = [1, 2, 3];
array.map(number => { 'number': number }); //SyntaxError!
به این دلیل که جاوااسکریپت دو { } رو به عنوان یک بلاک کد در نظر میگیره نه یک object.
قرار دادن object درون پرانتز میتونه این مشکل رو حل کنه:
const array = [1, 2, 3];
array.map(number => ({ 'number': number }) );
اگه object مورد نظر تعداد زیادی property داشته باشه هم میتونیم در خطوط جدید به صورت چند خطی اون رو بنویسیم در حالیکه هنوز از شکل مختصر arrow function استفاده میکنیم:
const array = [1, 2, 3];
array.map(number => ({
'number': number,
'propA': 'value A',
'propB': 'value B'
}));
5.عدم استفاده بیش از حد از کدهای تودرتو
سینتکس arrow function در جاوا اسکریپت کوتاهه که این ویژگی خوبیه؛ اما به عنوان یک اثر جانبی، اگر از تعداد زیادی arrow function درون هم به صورت تودرتو استفاده کنیم، همین سینتکس میتونه گیج کننده و ناخوانا بشه. فرض کنید در یک سناریوی فرضی، کلیدی داریم که با زدن اون یک درخواست به سرور ارسال میشه و وقتی جواب درخواست آماده بود، آیتم ها درون کنسول چاپ میشن:
myButton.addEventListener('click', () => {
fetch('/items.json')
.then(response => response.json())
.then(json => {
json.forEach(item => {
console.log(item.name);
});
});
});
همونطور که میبینیم زمان زیادی میبره تا بفهمیم این کد چطور کار میکنه و فهمیدن همین موضوع آسون نیست.
برای افزایش خوانایی توابع تودرتو، اولین راهحل اینه که متغیرهایی رو تعریف کنیم که هر کدوم یک arrow function رو نگهداری میکنن. هر متغیر باید به وضوح بیان کننده کاری که تابع درونش انجام میده باشه. بیاین کد رو بازنویسی کنیم:
const readItemsJson = json => {
json.forEach(item => console.log(item.name));
};
const handleButtonClick = () => {
fetch('/items.json')
.then(response => response.json())
.then(readItemsJson);
};
myButton.addEventListener('click', handleButtonClick);
با اصلاحاتی که انجام دادیم، هر arrow function متغیر مجزای خودش رو داره، کدهای تودرتو کمتر شدن (از 3 به 2 کاهش پیدا کردن که در حجم بالای کد میتونه خیلی موثرتر باشه) و در نهایت خوانایی کد ما افزایش پیدا کرده.
اما حتی بهتر! میتونیم تمام تابع رو بازنویسی و از سینتکس async/await استفاده کنیم که راه خیلی خوبی برای حل مشکل تودرتو شدن زیاد توابعه
const handleButtonClick = async () => {
const response = await fetch('/items.json');
const json = await response.json();
json.forEach(item => console.log(item.name));
};
myButton.addEventListener('click', handleButtonClick);
جمعبندی
استفاده از arrow function ها در جاوا اسکریپت بسیار فراگیر و مفیده. اونها باعث کمتر شدن حجم و راحت تر شدن درک کدهای ما میشن، به شرطی که هنگام استفاده از arrow function ها حواسمون به رعایت چند اصل ساده اما مهم باشه:
- arrow function ها در جاوااسکریپت ناشناس هستن به این معنی که به خودی خود اسمی ندارن. برای راحتی هنگام عملیات دیباگ کردن، بهتره توابع رو درون متغیرهایی با نام مناسب نگهداری کنیم.
- هنگامی که درون بدنه تابع فقط یک دستور وجود داره بهتره از فرم مختصر arrow function استفاده کنیم.
- عملگرهای <, >, =<, => شبیه به علامت => که arrow function رو تعریف میکنه هستن. هنگام استفاده از اونها درون arrow function ها احتیاط کنیم.
- زمانیکه در یک inline arrow function قصد استفاده از یک object داریم، اون رو درون پرانتز قرار بدیم چون جاوااسکریپت آکولادهای object رو به عنوان یک بلاک کد تشخیص میده و این باعث بروز ارور میشه.
- استفاده از توابع تودرتوی بیش از حد هدف کد رو مبهم میکنه. برای کاهش arrow function های تودرتو، اون ها رو درون متغیرهای مجزا قرار بدین. همچنین سعی کنید از ویژگیهای بهتری مثل async/await استفاده کنید.
شما چه اصول دیگهای رو میدونین که در استفاده از arrow function ها مفید هستن؟ برامون بنویسید.