عناصر داخلی تابع
در داخل هر تابع دو شیء خاص به نامهای arguments و this
وجود دارند. شیء arguments ، که
قبلا در مورد آن صحبت کردیم، دارای یک ویژگی به نام callee میباشد که به
تابعی اشاره میکند که arguments
متعلق به آن است. به مثال زیر توجه کنید که تابع فاکتوریل را به صورت بازگشتی
پیاده سازی نموده است:
function factorial(num) {
if (num <= 1)
return 1;
else
return num * factorial(num - 1);
}
این تابع به درستی کار خواهد کرد تا زمانیکه
نام تابع تغییر نکند. این نوع کد نویسی یک وابستگی شدید (Tightly Coupled) به نام تابع
دارد. این وابستگی میتواند با arguments.callee از بین برود: function factorial(num) {
if (num <= 1)
return 1;
else
return num * arguments.callee(num - 1);
}
در مثال فوق به جای نام تابع factorial در
مقابل return از arguments.callee
استفاده شده است. حال به مثال زیر توجه کنید: function factorial(num) {
if (num <= 1)
return 1;
else
return num * arguments.callee(num - 1);
}
var anotherFactorial = factorial;
factorial = function() {
return 0;
}
alert(anotherFactorial(5));
alert(factorial(5));
خروجی :
120
0
در مثال فوق، ابتدا تابع factorial
تعریف شده و سپس به متغیر anotherFactorial
نسبت داده شدهاست. سپس تابع factorial با
تعریف جدیدی جایگزین شده که مقدار 0 بر میگرداند. همانطور که مشاهده میکنید، تابع
بازگشتی از طریق arguments.callee
فراخوانی گردیده است. اما اگر به جای arguments.callee از نام تابع،
یعنی factorial
استفاده کرده بودیم، خروجی در هر دو مرحله 0 میبود. زیرا anotherFactorial نیز،
در داخل خود، تابع factorial
جایگزین شده با خروجی 0 را فراخوانی مینمود.
شیء دیگری که در توابع وجود دارد، شی this میباشد. این شیء به شیء ای اشاره میکند که تابع، متعلق به آن است یا برای آن فعالیت میکند. اگر تابعی به صورت عمومی تعریف شود، متعلق به شیء window میباشد.
بنابراین this در
این توابع به شیء window
اشاره میکند. به مثال زیر توجه کنید:
window.color = "red";
var o = { color: "blue" };
o.showColor = sayColor;
function sayColor() {
alert(this.color);
}
sayColor();
o.showColor();
خروجی :
"red"
"blue"
ابتدا ویژگی color را برای شیء window
تعریف کردیم. سپس شیء ای به نام o ایجاد نمودیم که دارای ویژگی color میباشد. همچنین تابعی به نام showColor را
برای آن تعریف نمودیم که تابع sayColor به آن نسبت داده شده است. در تابع
sayColor نیز
مقدار ویژگی color را
به صورت پیغامی نمایش میدهیم. زمانی که این تابع را فراخوانی مینماییم، شیء this
موجود در آن به شیء window
اشاره میکند؛ بنابراین مقدار "red" را
نمایش میدهد. سپس تابع showColor از
شیء o را
فراخوانی نمودیم که شیء this در
آن به شیء o
اشاره میکند. زیرا تابع showColor که
به تابع sayColor
اشاره میکند، متعلق به شیء o میباشد.
ویژگیها و توابع اشیاء ایجاد شده از Function
ویژگی caller
یکی از ویژگیهای توابع که میتواند مورد
استفاده قرار بگیرد، ویژگی caller میباشد. این ویژگی مشخص میکند که چه تابعی، تابع جاری را فراخوانی نموده است. اگر
فراخوانی تابع جاری در حوزهی عمومی (Global
Scope) صورت گرفته باشد، این ویژگی مقدار null بر میگرداند؛ در غیر اینصورت محتوای تابع فراخواننده برگردانده خواهد شد.
function outer() {
inner();
}
function inner() {
alert(inner.caller);
}
inner();
outer();
خروجی :
null
function outer() {
inner();
}
از آنجایی که inner در حوزهی عمومی فراخوانی شده است، inner.caller
مقدار null را
بر میگرداند. در خط بعدی تابع outer فراخوانی شده است که در داخل خود
تابع inner را
فراخوانی مینماید. در این شرایط inner.caller سورس کد تابع outer را
برمی گرداند که موجب فراخوانی تابع inner شده است. جهت کاهش وابستگی،
همانطور که در مبحث قبلی گفته شد، میتوانید بجای inner.caller از arguments.callee.caller
استفاده کنید. ویژگی length
ویژگی دیگری که برای توابع مورد استفاده قرار میگیرد، ویژگی length میباشد. این ویژگی تعداد Named
Arguments (پارامترهای نامی) تابع را بر میگرداند.
function sayName(name) {
alert(name);
}
function sum(num1,num2) {
return num1 + num2;
}
function sayHi() {
alert("Hi");
}
alert(sayName.length);
alert(sum.length);
alert(sayHi.length);
خروجی :
1
2
0
همانطور که در خروجی نیز مشاهده میکنید، تعداد
آرگومانهای هر یک از توابع تعریف شده نمایش یافته است. به عنوان مثال تابع sayName
دارای یک آرگومان ورودی است و خروجی نیز عدد 1 را نمایش داده است.
توابع apply() و call()
این دو تابع، جهت فراخوانی توابع، با یک مقدار
خاص برای شیء this
استفاده میشوند؛ در واقع مقدار شیء this را در بدنهی توابع تنظیم میکنند. همانطور که قبلا اشاره شد، شیء this ، به شیء ای اشاره میکند که تابع
متعلق به آن است. با توابع فوق میتوانیم اشارهگر this را با مقدار یا
شیء دیگری تنظیم کنیم. آرگومان اول هر دوی این توابع، مقداری است که باید به شیء this
اختصاص یابد. آرگومان بعدی تابع apply آرایهای است که آرگومانهای ورودی را
برای تابع فراخوانی شده فراهم میکند. آرگومانهای بعدی تابع call ، همان آرگومان هایی هستند که به صورت مجزا به تابع فراخوانی شده ارسال میگردند.
var color = "red";
var obj = { color: "blue" };
function sayColor(a, b) {
alert(a + " said " + b + ": " + this.color);
}
sayColor("Sohrab", "Mitra");
sayColor.apply(this, ["Sohrab", "Mitra"]);
sayColor.call(this, "Sohrab", "Mitra");
sayColor.apply(obj, ["Sohrab", "Mitra"]);
sayColor.call(obj, "Sohrab", "Mitra");
خروجی :
"Sohrab told Mitra: red"
"Sohrab told Mitra: red"
"Sohrab told Mitra: red"
"Sohrab told Mitra: blue"
"Sohrab told Mitra: blue"
همانطور که میدانید یک تابع به صورت پیش فرض
متعلق به شیء window میباشد. در سه فراخوانی اول، تابع sayColor ، شیء this ، به شیء window
اشاره میکند. بنابراین مقدار red را برای متغیر یا ویژگی color
نمایش میدهد. دو فراخوانی آخر که obj را به عنوان آرگومان اول ارسال مینمایند، یعنی شیء this
باید با مقدار obj
جایگزین شود. بنابراین مقدار blue را
برای ویژگی color ، که
متعلق به شی obj میباشد، نمایش میدهند.
تنها تفاوت call() و apply() ،
شیوهی ارسال آرگومانها به تابع مقصد میباشد. مزیت استفاده از توابع call() یا apply() این
است که میتوان یک شیء را به یک تابع تزریق نمود به گونهای که شیء، هیچ اطلاعی از
تابع مورد نظر نداشته باشد. این مزیت مورد استفادهی برخی الگوها و معماریها میباشد که در مباحث مربوطه در مورد آن بحث خواهد شد.
تابع bind()
این تابع نمونهای از یک تابع را ایجاد میکند و
شیء this آن تابع را، با آرگومان ارسالی به تابع bind ، مقداردهی مینماید.
var color = "red";
var obj = { color: "blue" };
function sayColor() {
alert(this.color);
}
var bindSayColor = sayColor.bind(obj);
bindSayColor();
خروجی :
"blue"
در مثال فوق، نمونهای از تابع sayColor
ایجاد شده است که شیء obj به
عنوان آرگومان ورودی تابع bind
ارسال شده است. یعنی مقدار this در
تابع bindSayColor به
شیء obj
اشاره میکند و مقدار ویژگی color شیء obj به
عنوان خروجی نمایش مییابد.