برنامه نویسی پیشرفته JavaScript - قسمت 4 - عناصر داخلی و ویژگی‌های تابع
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: شش دقیقه

عناصر داخلی تابع

در داخل هر تابع دو شیء خاص به نامهای 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 به عنوان خروجی نمایش می‌یابد.