با عرض سلام و ادب خدمت شما خوانندگان گرامی روکسو. در قسمت های قبلی در رابطه با نحوه ی تعریف توابع با کلیدواژه ی 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>
نکته: همانطور که مشخص است تابع بالا متعلق به هیچ شیء خاصی نیست اما این ظاهر قضیه است. در جاوا اسکریپت همیشه یک شیء سراسری و پیش فرض وجود دارد. در اسناد 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>
همانطور که در خروجی می بینیم شیء [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>
در این حالت کلیدواژه ی this
به شیء صاحب کد یعنی myObject اشاره می کند. اگر شیء بالا را تغییر دهیم و به جای آن کد زیر را قرار دهیم:
var myObject = { firstName:"John", lastName: "Doe", fullName: function () { return this; }
خروجی ما [object Object] خواهد بود که نشان دهنده ی این است که صاحب این متد همان myObject است.
به زبان ساده می گویم: اگر فراخوانی یک تابع با کلیدواژه ی 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>
در این حالت، کلیدواژه ی this
در یک constructor مقداری ندارد بلکه مقدار this
همان شیء جدیدی است که هنگام فراخوانی تابع ساخته می شود.
یکی از مواردی که جا دارد در مورد آن صحبت کنیم متد ()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>
همچنین با تغییر پارامتر call به کد زیر می توانیم آن را روی شیء person2 نیز اجرا کنیم:
person.fullName.call(person2);
بنابراین می توانید با دستور ()call
یک متد را روی شیء دیگری فراخوانی کنید!
امیدوارم از این قسمت لذت برده باشید. در قسمت بعد به سراغ دو تابع دیگر در زمینه ی فراخوانی خواهیم رفت و پس از آن به مبحث جذاب DOM خواهیم رسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.