در این مقاله قصد داریم تا با تایپ Function جاوااسکریپت که تایپ همه توابع در این زبان است، آشنا شویم.
در جاوااسکریپت، همه توابع یک آبجکت محسوب میشوند که نمونههایی از تایپ Function هستند. از آنجایی که توابع، آبجکت بهشمار میآیند مانند سایر آبجکتها دارای ویژگیها و روشهایی نیز میباشند.
هر تابع دو ویژگی مهم دارد: length
و prototype
.
length
تعداد آرگومانهای نامگذاری شده که در تعریف تابع مشخص شدهاند را تعیین میکند.prototype
به آبجکت تابع واقعی اشاره میکند.به مثال زیر توجه کنید:
function add(x, y) { return x + y; } console.log(add.length); // 2 console.log(add.prototype); // Object{}
تابع add()
دو آرگومان x و y را دریافت میکند. بنابراین، ویژگی length
مقدار ۲ را برمیگرداند.
به طور معمول، ما یک تابع را به صورت عادی و به شکل زیر فراخوانی میکنیم:
let result = add(10,20); console.log(result); // 30
همچنین میتوانیم یک تابع را با کلمه کلیدی new
به عنوان تابع سازنده فراخوانی کنیم:
let obj = new add(10,20);
ES6 شبه خاصیت new.target را معرفی کرده و به ما این امکان را میدهد تا بتوانیم تشخیص دهیم که آیا یک تابع معمولی یا تابع سازنده با استفاده از عملگر new
فراخوانی شده است یا خیر.
اگر تابعی به طور معمولی فراخوانی شود، new.target در این صورت undefined
است. با این حال، اگر تابع با استفاده از کلمه کلیدی new
به عنوان سازنده فراخوانی شود، new.target رفرنسی را به تابع سازنده برمیگرداند. به عنوان مثال:
function add(x, y) { console.log(new.target); return x + y; } let result = add(10, 20); let obj = new add(10, 20);
خروجی کد به صورت زیر است:
undefined [Function: add]
با استفاده از new.target میتوانیم نحوه فراخوانی یک تابع را نیز کنترل کنیم.
به عنوان مثال، برای جلوگیری از فراخوانی تابع add()
به عنوان سازنده با استفاده از کلمه کلیدی new
، میتوانیم با بررسی new.target به شکل زیر خطا ایجاد کنیم:
function add(x, y) { if (new.target) { throw 'The add function cannot be called as a constructor'; } return x + y; } let obj = new add(10, 20); console.log(obj);
یک آبجکت تابع سه متد مهم دارد: apply()
, call()
و bind()
.در ادامه هر کدام از این متدها را بررسی خواهیم کرد.
متدهای apply()
و call()
یک تابع با مقدار this
و آرگومانهای داده شده را فراخوانی میکنند.
تفاوت بین این دو متد در این است که ما باید آرگومانها را به عنوان یک آبجکت آرایه مانند به apply()
منتقل کنیم، در حالی که در تابع call()
آرگومانها را به صورت جداگانه ارسال میکنیم. مثلا:
let cat = { type: 'Cat', sound: 'Meow' }; let dog = { type: 'Dog', sound: 'Woof' }; const say = function (message) { console.log(message); console.log(this.type + ' says ' + this.sound); }; say.apply(cat, ['What does a cat say?']); say.apply(dog, ['What does a dog say?']);
خروجی به شکل زیر است:
What does a cat sound? Cat says Meow What does a dog sound? Dog says Woof
در این مثال، ابتدا دو آبجکت cat
و dog
را با دو ویژگی تعریف میکنیم:
let cat = { type: 'Cat', sound: 'Meow' }; let dog = { type: 'Dog', sound: 'Woof' };
در مرحله دوم تابع say()
را تعریف میکنیم که یک آرگومان میگیرد:
const say = function (message) { console.log(message); console.log(this.type + ' says ' + this.sound); };
سپس در مرحله سوم تابع say()
را توسط متد apply()
فراخوانی میکنیم:
say.apply(cat, ['What does a cat say?']);
در این مثال اولین آرگومان متد apply()
آبجکت cat
است. بنابراین this
در تابع say()
به آبجکت cat
اشاره میکند.
در مرحله چهارم تابع say()
را فراخوانی میکنیم و آبجکت dog
را به آن ارسال میکنیم:
say.apply(dog, ['What does a dog say?']);
اما اینجا this
در تابع say()
به آبجکت dog
اشاره میکند.
متد call()
مانند متد apply()
است اما فقط روشی که آرگومانها را به تابع ارسال میکنیم متفاوت است:
say.call(cat, 'What does a cat say?'); say.call(dog, 'What does a dog say?');
bind()
یک نمونه تابع جدید ایجاد میکند که این مقدار به آبجکتی که ما ارائه میکنیم محدود میشود. مثلا:
ابتدا یک آبجکت به نام car
تعریف میکنیم:
let car = { speed: 5, start: function() { console.log('Start with ' + this.speed + ' km/h'); } };
سپس آبجکت دیگری به نام aircraft
را تعریف میکنیم:
let aircraft = { speed: 10, fly: function() { console.log('Flying'); } };
aircraft
متد start()
ندارد. برای این که بتوانیم aircraft
را راهاندازی کنیم، میتوانیم به کمک bind()
از متد start()
آبجکت car
استفاده کنیم:
let taxiing = car.start.bind(aircraft);
در این عبارت، مقدار this
را در متد start()
آبجکت car
به آبجکت aircraft
تغییر میدهیم. متد bind()
تابع جدیدی را برمیگرداند که به متغیر taxiing
اختصاص داده شده است.
اکنون میتوانیم متد start()
را از طریق متغیر taxiing
فراخوانی کنیم:
taxiing();
در این صورت پیغام زیر را خواهیم دید:
Start with 10 km/h
همانطور که میبینید، متد bind()
یک تابع جدید ایجاد میکند که میتوانیم بعداً آن را اجرا کنیم در حالی که متد call()
بلافاصله تابع را اجرا میکند. همین موضوع تفاوت اصلی بین متدهای bind()
و call()
است.
از نظر فنی آبجکت aircraft
متد start()
آبجکت car
را از طریق متد apply()
, call()
و bind()
قرض میگیرد. به همین دلیل است که متدهای apply()
, call()
و bind()
نیز به عنوان توابع borrowing شناخته میشوند.
length
و prototype
apply()
, call()
و bind()