در این قسمت می خواهیم با مبحث مهمی از تغییرات ES6 صحبت کنیم که Arrow Function نام دارند (توابع پیکانی – چرا که نحوه ی نوشتن آن ها مثل نوک پیکان است =>
) و چند فایده ی مهم دارند. یکی از مهم ترین دلایل استفاده از Arrow function ها حل مشکل معروف this در جاوا اسکریپت است که در قسمت های قبلی با تغییر یک متغیر به نام self آن را حل کرده بودیم. از دیگر مزایای استفاده از Arrow function ها داشتن کد تمیزتر و خواناتر است.
برای شروع کار من دو فایل index.html و app.js را دارم. محتویات فایل HTML من به شکل زیر است:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>JavaScript Sandbox</title> </head> <body> <h1>Arrow Functions</h1> <script src="app.js"></script> </body> </html>
وارد فایل app.js خود شوید و در ابتدا یک تابع ساده تعریف کنید:
const sayHello = function() { console.log('Hello'); }
همه ی شما با این نوع از توابع آشنا هستید، یک تابع ساده که درون ثابتی به نام به نام sayHello قرار گرفته است و به آن function expression می گوییم. کار این تابع log کردن کلمه ی Hello در کنسول مرورگر است. برای صدا زدن چنین تابعی باید نام ثابت را به صورت یک تابع صدا بزنیم:
const sayHello = function() { console.log('Hello'); } sayHello();
تا اینجا چیز جدیدی وجود نداشت اما اگر بخواهیم این تابع را به یک Arrow Function تبدیل کنیم چطور؟ مراحل تبدیل چگونه خواهد بود؟ به زبان بسیار ساده برای تبدیل یک تابع عادی به arrow function ها باید ابتدا کلیدواژه ی function را حذف کرده و سپس به جای آن بین () و {} یک علامت پیکان =>
قرار دهیم:
const sayHello = () => { console.log('Hello'); }
به همین سادگی!
البته از آنجایی که دستور درون تابع (بدنه ی تابع) فقط یک خط و یک دستور است (log کردن Hello) می توانیم از روش خلاصه ی Arrow Function ها استفاده کنیم:
// One line function does not need braces const sayHello = () => console.log('Hello');
با ذخیره و اجرای این کد در کنسول مرورگر عبارت Hello را می بینیم. در این حالت دیگر نیازی به قرار دادن علامت های {} نداریم. بنابراین اگر بدنه ی تابع فقط یک خط بود و یا فقط بخواهیم چیزی را return کنیم می توانیم از این حالت خلاصه استفاده کنیم:
// One line returns const sayHello = () => 'Hello';
در این تابع رشته ی Hello تنها return می شود. البته همانطور که می دانید با return کردن یک رشته چیزی در مرورگر نمایش داده نمی شود بنابراین باید آن را console.log کنید. معادل قدیمی تابع بالا، این تابع است:
// Same as above const sayHello = function() { return 'Hello'; }
نکته: اگر بخواهید یک شیء literal (نوشته شده در همان قسمت از کد و به صورت دستی) را بدین روش return کنید به مشکل بر می خورید:
const sayHello = () => { msg: 'Hello' };
با log کردن تابع بالا با مقدار undefined روبرو می شویم چرا که curly braces ها (علامت های {}) به صورت بدنه ی تابع در نظر گرفته می شوند. راه حل این مشکل قرار دادن کل شیء درون پرانتز است:
// Return object const sayHello = () => ({ msg: 'Hello' });
سوال بعدی من این است: اگر در تعریف تابع پارامتر های مختلفی داشتیم چطور؟
const sayHello = (name) => console.log(`Hello ${name}`);
همانطور که می بینید هیچ مشکلی در اجرا نخواهیم داشت اما بهتر است کد بالا را به شکل زیر بنویسید:
// Single param does not need parenthesis const sayHello = name => console.log(`Hello ${name}`);
اگر توابع شما فقط یک پارامتر داشته باشند، نیازی به قرار دادن پرانتز نداریم و می توانیم پارامتر را مستقیما بنویسید اما اگر بیشتر از دو پارامتر داشته باشیم حتما به پرانتز ها نیاز خواهیم داشت:
// Multuiple params need parenthesis const sayHello = (firstName, lastName) => console.log(`Hello ${firstName} ${lastName}`);
اگر پرانتزهای بالا را از کد برداریم به خطای Uncaught SyntaxError برمی خوریم.
ما می توانیم از Arrow Function ها به عنوان Callback نیز استفاده کنیم و در این زمینه مشکلی نخواهیم داشت. به طور مثال فرض کنید چنین آرایه ای داشته باشیم:
const users = ['Nathan', 'John', 'William'];
حالا اگر بخواهیم با استفاده از تابع map روی تک تک اعضای این آرایه کار خاصی انجام دهیم، می گوییم:
const users = ['Nathan', 'John', 'William']; const nameLengths = users.map(function(name) { return name.length; }); console.log(nameLengths);
من می خواهم طول هر کدام از اعضای این آرایه را به دست بیاورم بنابراین چنین کدی نوشتم که خروجی آن به شکل زیر خواهد بود:
یعنی طول رشته ی اعضا به ترتیب 6 و 4 و 7 کاراکتر است. حالا می توانیم همین کد را به صورت خواناتر و تمیزتری بنویسیم:
const nameLengths = users.map(function (name) { return name.length; }); // Shorter const nameLengths = users.map((name) => { return name.length; });
اگر دو کد بالا را مقایسه کنید، مشخصا arrow function تمیزتر به نظر می رسد. حتی می توانیم arrow function بالا را خلاصه تر کرده و بگوییم:
const nameLengths = users.map(function (name) { return name.length; }); // Shorter const nameLengths = users.map((name) => { return name.length; }); // Shortest const nameLengths = users.map(name => name.length);
پارامتر ما یک پارامتر است بنابراین نیازی به پرانتز ندارد و بدنه ی تابع نیز فقط از یک دستور ساخته شده است بنابراین نیازی به علامت های {} نخواهد داشت.
ما می توانیم به کدهای جلسه ی قبل برگشته و به جای استفاده از توابع قدیمی از توابع ES6 استفاده کنیم:
// Get local text file data function getText() { fetch('test.txt') .then(res => res.text()) .then(data => { console.log(data); document.getElementById('output').innerHTML = data; }) .catch(err => console.log(err)); } // Get local json data function getJson() { fetch('posts.json') .then(res => res.json()) .then(data => { console.log(data); let output = ''; data.forEach(function(post) { output += `<li>${post.title}</li>`; }); document.getElementById('output').innerHTML = output; }) .catch(err => console.log(err)); } // Get from external API function getExternal() { fetch('https://api.github.com/users') .then(res => res.json()) .then(data => { console.log(data); let output = ''; data.forEach(function(user) { output += `<li>${user.login}</li>`; }); document.getElementById('output').innerHTML = output; }) .catch(err => console.log(err)); }
با مقایسه کردن این کد با کدهای جلسه ی قبل قطعا به خواناتر و تمیزتر بودن توابع Arrow در ES6 پی می برید. همچنین اگر از جلسات کتابخانه ی AJAX به یاد داشته باشید، دیگر نیازی به استفاده از آن متغیر self نداریم و می توانیم مستقیما از this استفاده کنیم! در قسمت بعدی نسخه ی دوم از کتابخانه ی easyHTTP خودمان را با استفاده از promise ها و توابع ES6 بازنویسی می کنیم.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.