فهرست مطالب
وقتی در یک متد داخل شیء از تابع پیکانی یا همان arrow function استفاده میکنید و ناگهان مقدار this برابر با undefined یا شیء سراسری window میشود، با یکی از گیجکنندهترین رفتارهای جاوااسکریپت روبهرو شدهاید. نگارش فلشی که در استاندارد ES6 معرفی شد، فقط روشی کوتاهتر برای تعریف توابع نیست؛ این ساختار رفتارهای پایهای مهمی دارد که اگر آنها را نشناسید، کدهای ناپایداری تولید خواهید کرد.
در این راهنما یاد میگیرید که چه زمانی استفاده از تابع معمولی ضروری است و چه زمانی توابع پیکانی گزینهی بهتری به شمار میروند.
تفاوتهای اصلی بر اساس مستندات رسمی
توابع معمولی که با کلمهی کلیدی function تعریف میشوند و توابع فلشی در چهار رفتار اساسی با یکدیگر تفاوت دارند:
۱. متغیر this اختصاصی ندارند: توابع معمولی مقدار this را وابسته به نحوهی فراخوانی مشخص میکنند. اگر تابعی به شکل متدِ یک شیء صدا زده شود، this همان شیء است. در توابع فلشی مقدار this به صورت لغوی (lexical) از محیط پیرامون به ارث میرسد و به شیء فراخواننده وابسته نیست.
۲. سازنده نیستند: نمیتوانید یک تابع فلشی را با کلمهی کلیدی new صدا بزنید. جاوااسکریپت در صورت اجرای چنین کدی خطای TypeError صادر میکند؛ بنابراین کلمهی کلیدی new.target نیز در این توابع در دسترس نیست.
۳. شیء arguments ندارند: در توابع سنتی به آرگومانهای ورودی از طریق arguments دسترسی دارید. در توابع فلشی این ساختار وجود ندارد و برای دریافت آرگومانهای متغیر باید از پارامترهای باقیمانده (rest parameters با نماد ...) استفاده کنید.
۴. ژنراتور نمیشوند: امکان استفاده از کلمهی کلیدی yield در بدنهی توابع فلشی وجود ندارد و نمیتوانید آنها را به عنوان تابع ژنراتور بسازید.
نحوهی نگارش و بازگشت خودکار مقادیر
توابع فلشی به دو صورت نوشته میشوند: بدنهی عبارتی (expression body) و بدنهی بلوکی (block body).
اگر تابع فقط شامل یک عبارت ساده باشد، نیازی به آکولاد و کلمهی کلیدی return نیست و خروجی عبارت به طور خودکار بازگردانده میشود. اگر بدنه بیش از یک دستور داشته باشد، باید آکولاد بگذارید و مقدار بازگشتی را با return مشخص کنید:
javascript// بازگشت خودکار در بدنهی عبارتی
const double = n => n * ۲;
// بدنهی بلوکی همراه با دستور مشخص
const sumAndLog = (a, b) => {
const result = a + b;
console.log("جمع:", result);
return result;
};
مقایسه رفتار this در یک مثال واقعی
برای درک تفاوت عملی، یک شیء ساده را با دو متد در نظر بگیرید. متد اول با تابع معمولی و متد دوم با تابع فلشی تعریف شده است:
javascript"use strict";
const counter = {
count: ۱۰,
// متد معمولی: this به خود شیء counter اشاره دارد
regularMethod: function () {
return this.count;
},
// متد فلشی: this از محیط اطراف گرفته میشود نه خود شیء
arrowMethod: () => {
return this.count;
}
};
console.log(counter.regularMethod()); // خروجی: ۱۰
console.log(counter.arrowMethod()); // خروجی: undefined (یا خطا در حالت strict)
در کد بالا، تابع regularMethod متوجه میشود که از روی شیء counter فراخوانی شده، بنابراین this برابر با همان شیء است. اما تابع فلشی مقدار this را از محیط ماژول یا پنجره سراسری میگیرد که در آن متغیری به نام count وجود ندارد.
در مقابل، وقتی میخواهید کالبکی درون متدی از یک شیء تعریف کنید، رفتار توابع فلشی مزیت بزرگی است. در تابع سنتی کالبک ممکن بود this را گم کند و برنامهنویسان مجبور به استفاده از متدهایی مثل bind میشدند، اما تابع فلشی دقیقاً همان this متد پیرامون را در دست نگه میدارد:
javascriptconst team = {
name: "دیناکد",
members: ["سارا", "علی"],
printMembers() {
// تابع فلشی مقدار this متد printMembers را حفظ میکند
this.members.forEach(member => {
console.log(member + " عضو تیم " + this.name + " است.");
});
}
};
team.printMembers();
// خروجی:
// سارا عضو تیم دیناکد است.
// علی عضو تیم دیناکد است.
دو اشتباه رایج که باید از آنها دوری کنید
۱. بازگرداندن اشتباهی شیء در یک خط
اگر بخواهید یک شیء جاوااسکریپتی را در بدنهی تکخطی تابع فلشی برگردانید، مفسر جاوااسکریپت آکولادهای شیء را به عنوان بدنهی بلوکی شناسایی میکند و خروجی undefined خواهد شد:
javascript// اشتباه: جاوااسکریپت نام خصوصیت را برچسب تلقی میکند
const makeUserWrong = (name) => { name: name };
console.log(makeUserWrong("رضا")); // undefined
// درست: شیء را درون پرانتز قرار دهید
const makeUserRight = (name) => ({ name: name });
console.log(makeUserRight("رضا")); // { name: 'رضا' }
۲. استفاده به عنوان سازنده با new
نمیتوانید توابع پیکانی را مانند توابع قدیمی برای ساخت اشیاء جدید به کار ببرید:
javascriptconst Person = (name) => {
this.name = name;
};
// اجرای این خط با خطای TypeError مواجه میشود:
// TypeError: Person is not a constructor
const user = new Person("مهدی");
برای تعریف سازنده یا کلاس باید از سینتکس رسمی class یا توابع معمولی استفاده کنید.
قدم بعدی
قاعدهی سادهای را برای انتخاب به خاطر بسپارید: هرگاه کالبکی به متدهای آرایه مانند map و filter پاس میدهید یا به ارث بردن this محیط نیاز دارید، از arrow function استفاده کنید. هرگاه تابعی را به عنوان متد مستقیم یک شیء تعریف میکنید یا ساختار تابعی با قابلیت ساخت شیء مد نظر شماست، تابع معمولی بنویسید.
اگر قصد دارید مفاهیم اسکوپ، زنجیره پروتوتایپ و مدل اجرای کد در جاوااسکریپت را به شکلی اصولی تمرین کنید، دورهی جاوااسکریپت از صفر تا برنامهنویس مسیر یادگیری را گامبهگام در اختیارتان میگذارد.




نظرها
اولین نفری باشید که نظر میدهدسؤالتان را بپرسید یا تجربهتان را بنویسید تا نویسندهی مطلب پاسخ بدهد.