فراخوانی توابع جاوا اسکریپتی

09 فروردین 1398
Advanced-Javascript-back-call

با عرض سلام و ادب خدمت شما خوانندگان گرامی روکسو. در قسمت های قبلی در رابطه با نحوه ی تعریف توابع با کلیدواژه ی function و همچنین پارامتر های توابع صحبت کردیم. در این قسمت به بحث فراخوانی توابع رسیده ایم و می خواهیم انواع فراخوانی ها در توابع جاوا اسکریپتی را بررسی کنیم.

فراخوانی توابع

همانطور که می دانید کدهای داخل یک تابع جاوا اسکریپتی اجرا نمی شوند مگر آنکه تابع فراخوانی شود. «صدا زدن» و یا «فراخوانی» که در انگلیسی به ترتیب معادل call a function و invoke a function هستند با یکدیگر هیچ تفاوتی ندارند و شما می توانید از هر کدام که دوست داشتید استفاده کنید.

مثال زیر یک مثال ساده از فراخوانی توابع جاوا اسکریپتی است:

<!DOCTYPE html>
<html>
<body>

<h2>JavaScript Functions</h2>

<p>The global function (myFunction) returns the product of the arguments (a ,b):</p>

<p id="demo"></p>

<script>
function myFunction(a, b) {
  return a * b;
}
document.getElementById("demo").innerHTML = myFunction(10, 2); 
</script>

</body>
</html>

مشاهده ی خروجی در JSBin

نکته: همانطور که مشخص است تابع بالا متعلق به هیچ شیء خاصی نیست اما این ظاهر قضیه است. در جاوا اسکریپت همیشه یک شیء سراسری و پیش فرض وجود دارد. در اسناد HTML شیء سراسری همان صفحه ی HTML است بنابراین تابعی که بالاتر نوشته ایم متعلق به شیء صفحه ی HTML است. اما زمانی که این سند HTML درون یک مرورگر قرار می گیرد، شیء اصلی همان شیء window می باشد بنابراین می توان کد بالا را به صورت زیر نوشت:

<!DOCTYPE html>
<html>
<body>

<h2>JavaScript Functions</h2>

<p>Global functions automatically become window methods. Invoking myFunction() is the same as invoking window.myFunction().</p>

<p id="demo"></p>

<script>
function myFunction(a, b) {
  return a * b;
}
document.getElementById("demo").innerHTML = window.myFunction(10, 2); 
</script>

</body>
</html>

و میبینیم که myFunction دقیقا همان window.myFunction است.

اگر چه این روش، روش محبوب و ساده ی فراخوانی و ایجاد توابع است اما بهترین راه نیست چرا که در برخی از موارد متغیرهای سراسری، متدها یا توابع می توانند به نام هایی که از قبل در شیء سراسری وجود دارند، همسان باشند و باعث ایجاد باگ در برنامه ی شما شوند.

همانطور که قبلا هم در این باره صحبت کرده ایم، کلیدواژه ی this به شیء ای اشاره می کند که صاحب کد فعلی است. بنابراین اگر این کلیدواژه را در یک تابع به کار ببریم، this به شیء ای برمیگردد که صاحب این تابع است.

سوال: اگر کد ما بدون شیء خاصی باشد، کلیدواژه ی this چه چیزی را نشان می دهد؟

پاسخ: اگر تابع یا کدهای شما درون شیء خاصی نباشند، کلیدواژه ی this به شیء سراسری اشاره می کند. به طور مثال می توانیم کد زیر را بنویسیم تا شیء اصلی مشخص شود:

<!DOCTYPE html>
<html>
<body>

<h2>JavaScript Functions</h2>

<p>In HTML the value of <b>this</b>, in a global function, is the window object.</p>

<p id="demo"></p>

<script>
var x = myFunction();
function myFunction() {
  return this;
}
document.getElementById("demo").innerHTML = x; 
</script>

</body>
</html>

مشاهده ی خروجی در JSBin

همانطور که در خروجی می بینیم شیء [object Window] به ما برگردانده می شود.

هشدار: استفاده از [object Window] به عنوان یک متغیر باعث crash و متوقف شدن کامل برنامه ی شما می شود. به عنوان قانونی کلی به شما می گویم که هیچ گاه به توابع، اشیاء و به طور کلی کدهای از پیش نوشته شده ی جاوا اسکریپت دست نزنید.

فراخوانی توابع به عنوان متد

همانطور که می دانید می توانیم توابع جاوا اسکریپت را به عنوان متدهای اشیاء مختلف تعریف کنیم. در چنین حالتی باید تعریف تابع را درون شیء مورد نظر قرار دهیم:

<!DOCTYPE html>
<html>
<body>

<h2>JavaScript Functions</h2>

<p>myObject.fullName() will return John Doe:</p>

<p id="demo"></p>

<script>
var myObject = {
  firstName:"John",
  lastName: "Doe",
  fullName: function() {
    return this.firstName + " " + this.lastName;
  }
}
document.getElementById("demo").innerHTML = myObject.fullName(); 
</script>

</body>
</html>

مشاهده ی خروجی در JSBin

در این حالت کلیدواژه ی this به شیء صاحب کد یعنی myObject اشاره می کند. اگر شیء بالا را تغییر دهیم و به جای آن کد زیر را قرار دهیم:

var myObject = {
  firstName:"John",
  lastName: "Doe",
  fullName: function () {
    return this;
  }

خروجی ما [object Object] خواهد بود که نشان دهنده ی این است که صاحب این متد همان myObject است.

فراخوانی تابع از طریق Function Constructor

به زبان ساده می گویم: اگر فراخوانی یک تابع با کلیدواژه ی new انجام شود، این فراخوانی از طریق constructor بوده است. در ظاهر به نظر می رسد که یک تابع دیگر می سازید اما از آن جا که توابع جاوا اسکریپتی از نوع اشیاء هستند، یک شیء جدید می سازید:

<!DOCTYPE html>
<html>
<body>

<h2>JavaScript Functions</h2>

<p>In this example, myFunction is a function constructor:</p>

<p id="demo"></p>

<script>
function myFunction(arg1, arg2) {
  this.firstName = arg1;
  this.lastName  = arg2;
}

var x = new myFunction("John","Doe")
document.getElementById("demo").innerHTML = x.firstName; 
</script>

</body>
</html>

مشاهده ی خروجی در JSBin

در این حالت، کلیدواژه ی this در یک constructor مقداری ندارد بلکه مقدار this همان شیء جدیدی است که هنگام فراخوانی تابع ساخته می شود.

استفاده از تابع ()call

یکی از مواردی که جا دارد در مورد آن صحبت کنیم متد ()call است. با استفاده از این متد می توانید متدهایی داشته باشید که روی اشیاء دیگر اجرا می شوند.

همانطور که میدانید در زبان جاوا اسکریپت تمام توابع، متدهای شیء خاصی هستند. به شکلی که اگر تابعی شیء خاص خود را نداشته باشد، بخشی از شیء سراسری جاوا اسکریپت خواهد بود.

حالا کاری که متد ()call برای ما انجام می دهد این است که شیء مورد نظر را به عنوان پارامتر دریافت کرده و متد خاصی را روی آن اجرا می کند.

سوال: این قابلیت به چه درد ما می خورد؟

پاسخ: به خودی خود بی فایده به نظر می رسد اما اگر خوب دقت کنید متوجه می شوید که یک شیء می تواند از طریق ()call  از متدی استفاده کند که متعلق به شیء دیگری است! بنابراین می توانید از زیاده نویسی های زیادی جلوگیری کرده و در عین حال در وقت خود صرفه جویی کنید. تصور کنید که متدهای یک شیء را روی هر شیء ای که خواستید پیاده سازی کنید! این تابع از توابع بسیار به درد بخور جاوا اسکریپت است.

برای مثال سه شیء تعریف می کنیم و نام آن ها را person و person1 و person2 گذاشته و در شیء person یک متد به نام fullName تعریف می کنیم. حالا می خواهیم کاری کنیم که شیء person1 بدون داشتن متدِ fullName بتواند از آن استفاده کند:

<!DOCTYPE html>
<html>
<body>

<h2>JavaScript Functions</h2>
<p>This example calls the fullName method of person, using it on person1:
</p>

<p id="demo"></p>

<script>
var person = {
  fullName: function() {
    return this.firstName + " " + this.lastName;
  }
}
var person1 = {
  firstName:"John",
  lastName: "Doe"
}
var person2 = {
  firstName:"Mary",
  lastName: "Doe"
}
var x = person.fullName.call(person1); 
document.getElementById("demo").innerHTML = x; 
</script>

</body>
</html>

مشاهده ی خروجی در JSBin

همچنین با تغییر پارامتر call به کد زیر می توانیم آن را روی شیء person2 نیز اجرا کنیم:

person.fullName.call(person2);

بنابراین می توانید با دستور ()call یک متد را روی شیء دیگری فراخوانی کنید!

امیدوارم از این قسمت لذت برده باشید. در قسمت بعد به سراغ دو تابع دیگر در زمینه ی فراخوانی خواهیم رفت و پس از آن به مبحث جذاب DOM خواهیم رسید.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری جاوا اسکریپت پیشرفته توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.