عناصر داخلی تابع
در داخل هر تابع دو شیء خاص به نامهای argumentsو this وجود دارند. شیء arguments، که قبلا در مورد آن صحبت کردیم، دارای یک ویژگی به نام calleeمیباشد که به تابعی اشاره میکند که arguments متعلق به آن است. به مثال زیر توجه کنید که تابع فاکتوریل را به صورت بازگشتی پیاده سازی نموده است:
function factorial(num) { if (num <= 1) return 1; else return num * factorial(num - 1); }
function factorial(num) { if (num <= 1) return 1; else return num * arguments.callee(num - 1); }
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(); }
ویژگی 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به عنوان خروجی نمایش مییابد.