Function.apply و Function.call در جاوااسکریپت

Function.apply و  Function.call در جاوااسکریپت
در زبان برنامه نویسی جاوااسکریپت، توابع جزو اشیاء هستند، و توابع جاوااسکریپت دارای متد و ویژگی هستند.
call() و apply() دو متد پیشفرض توابع جاوااسکریپت هستند. هر دو متد توانایی فراخوانی توابع رو دارند و در هر دومتد باید آبجکت والد رو به عنوان پارامتر اول داشته باشیم.
خرید شارژ ایرانسل
خرید شارژ ایرانسل، همراه اول، رایتل | خرید بسته های اینترنت ایرانسل | etore.ir
خرید سرور مجازی
ارائه سرور مجازی SSD NVMe برای اولین بار در ایران ؛ نهایت سرعت را تجربه کنید.
خرید شارژ ایرانسل
خرید شارژ ایرانسل، همراه اول، رایتل | خرید بسته های اینترنت ایرانسل | etore.ir
خودتان را اینجا معرفی کنید

برای شروع کار مثالی ساده رو باهم بررسی کنیم :
function myFunction(a, b) {
    return a * b;
}
myObject = myFunction.call(myObject, 10, 2);     // return 20
و برای apply() :
function myFunction(a, b) {
    return a * b;
}
myArray = [10, 2];
myObject = myFunction.apply(myObject, myArray);  //  return 2
اگر دقت کنید هر دو متد، myObject رو به عنوان والدشون و پارامتر اول قرار دادن و تنها تفاوت این دو تابع در نحوه‌ی ارسال آرگومان ها می باشد که در متد call  به صورت آرگومان‌هایی تکی ارسال می‌شوند ولی در apply میتوان به صورت آریه ارسال کرد.
باید دقت کنیم در حالت strict mode پارامتر اولی که ارسال میشه مقدار this  رو در تابع فراخوانی شده خواهد داشت حتی در صورتیکه آبجکت نباشد. در حالت non-strict mode  اگر پارامتر اول null  و یا undefined  باشد، با global object  ریپلیس می‌شود.

enlightenedStrict mode از ECMA SCRIPTورژن 5 اعمال شد و در اینترنت اکسپلورر 10 ، فایرفاکس 4 ، کروم ورژن 13 ، سافاری ورژن 5.1 و اپرا ورژن 12 به بعد ساپورت میشه. در این حالت تمام سینتکس های جاوااسکریپت باید رعایت بشه برای مثال در حالت strict mode  ما دیگه نمیتونیم متغیری رو بدون اعلان و تعریفش استفاده کنیم و Error  خواهیم داشت و ....
برای مطالعه بیشتر این موضوع میتونید لینک "JavaScript Use Strict" رو در سایت " W3schools " مطالعه نمائید. :)

enlightenedاین نکته رو به یاد داشته باشیم که با استفاده از این دو متد ما میتونیم مقدار this  رو در تابعی که فراخوانی میکنیم ست کنیم.

مواردی که تا الان ذکر کردیم کلیاتی بودند برای اینکه با موضوع تا حدودی درگیر بشید و حالا بیایید با هم بیشتر موضوع رو باز کنیم و بحث کنیم wink

ادامه بحث رو با مثالی دیگه ادامه بدیم  :
var x = 10;
function f()
{
    alert(this.x);
}
f();
در اینجا ما یک تابع gloabal داریم به نام f که درون این تابع کلمه‌ی کلیدی this به مقدار x  اشاره میکنه اما نکته اینجاست که ما به هیچ تابعی اشاره نمیکنیم و مقداری رو از میان آبجکت‌ها فراخوانی نمیکنیم، پس رفرنس ما برای فراخوانی کدوم آبجکته؟ و چطور تشخیص میده که مقدار x رو از کجا فراخوانی کنه؟! بله درسته! gloabal object  رفرنس ما خواهد بود و gloabal object مکانیه که ما x  رو  در اون تعریف کردیم. پس مقداری که در آخر برای ما نمایش داده شود مقدار 10 خواهد بود.

با بررسی مثال زیر موضوع جذابتر خواهد شد، let's go  wink
var x = 10;
var o = { x: 15 };
 
function f()
{
    alert(this.x);
}
f();  // ?
f.call(o); // ??
مطمئنا حدس زدید که جای علامت سوال اول مقدار 10 قرار خواهد گرفت چونکه رفرنس ما gloabal object می‌باشد.
مقدار دوم (؟؟) هم مقدار 15 خواهد بود چونکه ما با استفاده از متد call  به آبجکت o اشاره میکنیم و مقدار xی که در آبجکت o تعریف شده است مقدار 15 می‌باشد. پس همانطور که دقت کردید ما میتونیم مقدار this  را به این نحو تغییر بدیم.

همچنین میتونیم مقداری رو با استفاده از متد call  ارسال کنیم :
var x = 10;
var o = { x: 15 };
function f(message)
{
    alert(message);
    alert(this.x);
}
f("invoking f"); // invoking f 10
f.call(o, "invoking f via call"); // invoking f via call 15
متد apply دقیقا مانند متد Call  عمل میکنه با این تفاوت که با استفاده از متد apply  میتونیم مقداری رو به عنوان آرایه ارسال کنیم :
var x = 10;
var o = { x: 15 };
function f(message)
{
    alert(message);
    alert(this.x);
}
 
f("invoking f");
f.apply(o, ["invoking f through apply"]);
مثالی پیچیده تر :
var o = { x: 15 };
function f1(message1)
{
    alert(message1 + this.x);
}
function f2(message1, message2)
{
    alert(message1 + (this.x * this.x) + message2);
}
function g(object, func, args)
{
    func.apply(object, args);
}
g(o, f1, ["the value of x = "]);
g(o, f2, ["the value of x squared = ", ". Wow!"]);
همانطور که در مثال بالا میبینید میشه گفت کمی کدها پیچیده شده و ما میتونیم به صورت فانکشنال و بهنه تر بنویسیم و به این صورت عمل میکنیم :
اگر یادتون باشه آرگومان‌هایی که به تابع ارسال میشن رو میتونیم مقدار length رو بگیریم و تعداد اونها رو بدست بیاریم برای مثال :
function f(message)
{
    for(var i = 1; i < arguments.length; i++)
    {
        message += arguments[i];
    }
    alert(message);
}
// this will say "Hello"
f("H", "e", "l", "l", "o");
همانطور که مشاهده میکنید با محاسبه‌ی length  آرگومانهایی که ارسال شده اند میتونیم برنامه رو به صورتی بهینه بنویسیم.
اکنون با هم مثال قبلی رو به صورت زیر بازنویسی میکنیم :
var o = { x: 15 };
function f(message1, message2)
{
    alert(message1 + (this.x * this.x) + message2);
}
function g(object, func)
{          
    // arguments[0] == object
    // arguments[1] == func 
     
    var args = []; // empty array
    // copy all other arguments we want to "pass through"
    for(var i = 2; i < arguments.length; i++)
    {
        args.push(arguments[i]);
    }
    func.apply(object, args);
}
g(o, f, "The value of x squared = ", ". Wow!");

ما در این پارت آموزشی مفاهیم call و apply  رو به صورت تئوری توضیح دادیم و برای اینکه درک این موضوع براتون تثبیت بشه لازمه که در پروژه هایی که دارید از این متدها استفاده کنید. امیدوارم به درک این موضوع کمکی کرده باشیم .

و نکته‌ی مهم اینکه مثل همیشه از تک تک لحظاتتون مخصوصا موقع کدنویسی لذت ببرید.
شاد باشید wink
 

میکائیل اندیشه هستم، چند سالی میشه در حوزه Front-End کار میکنم و بیشتر علاقه ی من در زمینه برنامه نویسی JavaScript , jQuery و تکنولوژی های مرتبط هست و فعلا نیز در این حوزه مطالعه میکنم ... :)

نظرات و سوالات کاربران

ارسال پاسخ محمود
محمود
دوشنبه ۱۷ اسفند ۱۳۹۴ ۰۰:۵۶
برادر چقدر بنیادی رفتی تو جاوا اسکریپت
بیشتر تمرکز این زبان روی DOMوBOM وevent هاست اگه اشتباه نکنم
اما واقعاً من چندسالیه دارم باهاش کار میکنم و با هیچ گره خاصی بر نخوردم و همچنین مطالبی که شما بیان میکنید رو نمیدونستم.
و مشکل خاصی هم برام پیش نیومده
اما برام سواله تا حالا این مباحث کجا بودن؟ یا اصن من کجا بودم؟ :)))
ارسال پاسخ رضا
رضا
شنبه ۱۷ بهمن ۱۳۹۴ ۲۰:۲۰
در پاسخ به دیدگاه رضا ارسال شده در شنبه ۱۷ بهمن ۱۳۹۴ ۰۰:۴۷
سلام خیلی هم عالی خیلی بهم کمک کردید ممنون :)
یک سوال داخل یک فانکشن IIFE , یک همچین چیزی دیدم function.call(this); اینجا چه اتفاقی میفته ممنون میشم راهنمایی کنید.
سلام ممنونم که جواب دادید کد اصلی داخل سایت کد پین هست با این لینک codepen.io/kenwheeler/pen/LvGjK/
ارسال پاسخ میکائیل
میکائیل
شنبه ۱۷ بهمن ۱۳۹۴ ۱۳:۰۱
در پاسخ به دیدگاه میکائیل ارسال شده در یکشنبه ۱۱ بهمن ۱۳۹۴ ۱۷:۰۸
خواهش میکنم سوران عزیز خوشحالم که مورد پسندتون واقع شده :)
ممنون رضا جان، خوشحالم مفید بوده ، برای این سوالی که فرمودید باید کد اصلی رو ببینم تا بهتون بگم دقیق چیکار میکنه ( وفکر کنم بتونی توی تالار گفتمان مجید آنلاین یک تایپیک ایجاد کنی) ولی برای اینکه بتونی مفهومش رو کامل درک کنی اول باید بدونی که خود this چطور کار میکنه (اگر سرچ کنی توی مجیدآنلاین مقاله ای در رابطه با this وجود داره) و پس از اون باید بفهمی که درون تابعی که میگی مقدار this چیه؟ و برای اینکار درون تابع console.log(this) رو بنویس و توی کنسول ببین مقدار this چیه ، چون در توابع IIFE معمولا تابع یکبار اجرا میشه همانطور که در مبحث قبلی توابع اشاره کردم! و هدف از اینجا فکر کنم باید این باشه که مقدار this رو که هرچی که هست یکبار روی کل توابع دیگه ست کنه.
ارسال پاسخ رضا
رضا
شنبه ۱۷ بهمن ۱۳۹۴ ۰۰:۴۷
سلام خیلی هم عالی خیلی بهم کمک کردید ممنون :)
یک سوال داخل یک فانکشن IIFE , یک همچین چیزی دیدم function.call(this); اینجا چه اتفاقی میفته ممنون میشم راهنمایی کنید.
ارسال پاسخ میکائیل
میکائیل
یکشنبه ۱۱ بهمن ۱۳۹۴ ۱۷:۰۸
در پاسخ به دیدگاه سوران خضری ارسال شده در یکشنبه ۱۱ بهمن ۱۳۹۴ ۱۳:۰۰
خیلی عالی بود
در وب سایت های فارسی کمتر به مسایل عمیق تر و فنی تر جاوا اسکریپت پرداخته میشه و فقط چیزهایی سطحی رو میبینیم که توی همه سایت ها تکرار میشه
ممنون از شما
خواهش میکنم سوران عزیز خوشحالم که مورد پسندتون واقع شده :)
ارسال پاسخ سوران خضری
سوران خضری
یکشنبه ۱۱ بهمن ۱۳۹۴ ۱۳:۰۰
خیلی عالی بود
در وب سایت های فارسی کمتر به مسایل عمیق تر و فنی تر جاوا اسکریپت پرداخته میشه و فقط چیزهایی سطحی رو میبینیم که توی همه سایت ها تکرار میشه
ممنون از شما