توابع در جاوااسکریپت به دو روش مختلف میتوانند تعریف شوند. یکی از این روشها، تابع arrow نام دارد. این تابع یکی از ویژگیهای جدیدی هست که در ES6 معرفی شده است و یک شکل سادهتر و کوتاهتر برای نوشتن تابع میباشد. اگرچه هر دو نوع توابع کار یکسانی را انجام میدهند، اما تفاوتهایی نیز بین آنها وجود دارد. در این مقاله قصد داریم تا بیشتر در مورد تفاوت بین توابع معمولی و توابع arrow صحبت کنیم.
مثالی از یک تابع arrow در زیر داریم:
// (param1, param2, paramN) => expression // ES5 var add = function(x, y) { return x + y; }; // ES6 let add = (x, y) => { return x + y };
سینتکس تابع arrow به توسعه دهنده اجازه میدهد تا تابع را با تعداد خط کد کمتر بنویسد و به همان نتیجه دست پیدا کند.
اگر تابع یک خطی باشد، آکولاد لازم نیست. در این حالت، مثال بالا را میتوانیم به شکل زیر بنویسیم:
let add = (x, y) => x + y;
اگر تابع فقط یک آرگومان داشته باشد، حتی پرانتز نیز لازم نیست:
let squareNum = x => x * x;
سوالی که پیش میآید این است، اگر تابع هیچ آرگومانی نداشته باشد چه اتفاقی میافتد؟
let sayHi = _ => console.log(“Hi”);
توابع arrow اتصال آرگومان ندارند. یعنی نمیتوانند در مقدار آرگومانها تغییر ایجاد کنند. با این حال، آنها به آبجکت آرگومانهای نزدیکترین تابع غیر arrow والدشان دسترسی دارند. همچنین برای گرفتن آرگومانهای ارسال شده به توابع arrow از پارامترهای نامگذاری شده و پارامتر Rest استفاده میشود.
به عنوان مثال، در توابع معمولی:
let myFunc = { showArgs(){ console.log(arguments); } }; myFunc.showArgs(1, 2, 3, 4);
در خروجی نهایی، آبجکت آرگومان نمایش داده میشود.
اما در توابع arrow:
let myFunc = { showArgs : () => { console.log(...arguments); } }; myFunc.showArgs(1, 2, 3, 4);
در خروجی نهایی هنگام فراخوانی تابع، خطای Uncaught ReferenceError: arguments is not defined
رخ میدهد.
یکی دیگر از مواردی که تفاوت بین توابع معمولی و توابع arrow به حساب میآید، کلمه کلیدی this است. در تابع arrow، برخلاف تابع معمولی این ویژگی خاص وجود ندارد و مقدار this در داخل تابع در طول چرخه عمر آن، ثابت باقی میماند و به نزدیکترین تابع غیر arrow والدش مربوط میشود.
به عنوان مثال:
let me = { name: "Ashutosh Verma", thisInArrow:() => { console.log("My name is " + this.name); // no 'this' binding here }, thisInRegular(){ console.log("My name is " + this.name); // 'this' binding works here } }; me.thisInArrow(); me.thisInRegular();
هنگام فراخوانی تابع ()thisInArrow کلمه کلیدی this کار نمیکند و اتصال(bind) صورت نمیگیرد، در نتیجه خروجی "My name is"
میشود. اما در زمان فراخوانی تابع ()thisInRegular، خروجی کد "My name is Ashutosh Verma"
است.
توابع معمولی که با عبارت function ایجاد میشوند، قابل ساخت(construct) و فراخوانی هستند. پس میتوان آنها را با استفاده از کلمه کلیدی new فراخوانی کرد.
اما توابع arrow فقط قابل فراخوانی هستند و قابلیت ساخته شدن ندارند، یعنی این توابع هرگز نمیتوانند به عنوان توابع سازنده(constructor) مورد استفاده قرار بگیرند. پس نمیتوان آنها را با کلمه کلیدی new فراخوانی کرد.
let add = (x, y) => console.log(x + y); new add(2,3);
در مثال بالا، وقتی new add(2,3)
فراخوانی میشود، خطای TypeError: add is not a constructor
رخ میدهد.
در توابع arrow آرگومانهای مختلف، چه در حالت strict و چه در حالت non-strict نمیتوانند نامهای تکراری داشته باشند.
به عنوان مثال، کد جاوااسکریپت زیر در حالت معمولی یک کد معتبر است:
function add(x, x){}
اما هنگام استفاده از حالت strict، معتبر نخواهد بود:
'use strict'; function add(x, x){} // SyntaxError: duplicate formal argument x
اما در توابع arrow آرگومانها با نامهای تکراری، چه حالت strict و چه حالت non-strict همیشه نامعتبر هستند.
(x, x) => {} // SyntaxError: duplicate argument names not allowed in this context