על המתודות call, apply ו-bind ב-JavaScript

המתודות call, apply ו-bind ב-JavaScript הן מתודות שימושיות מאוד אך ההבדל ביניהן עלול לבלבל.
אז למה הן משמשות ומה ההבדלים ביניהן? במאמר הבא.

דומות אבל שונות

באופן כללי, המתודות call, apply ו-bind ב-JavaScript משמשות לביצוע פונקציה כאשר ה-this בתוכה משתנה בהתאם לקריאה הנוכחית, אך כל אחת מהן שונה במקצת מהאחרת.

()call

המתודה call קוראת לפונקציה ומבצעת אותה באופן מיידי. הארגומנט הראשון שהיא תקבל יהיה האובייקט שה-this בפונקציה יצביע עליו.
נשמע מאוד מסובך, לא? לא 🙂
דוגמה קצרה שתבהיר עד כמה זה פשוט:

let sayHello = function() {
    console.log('Hello! My name is ' + this.name);
}

let david = {
    name: 'David'
}

sayHello.call(david);

הפלט אל ה-console:

הפלט שיוצא מהפונקציה sayHello כאשר האובייקט david מועבר אליה.
הפלט שיוצא מהפונקציה sayHello כאשר האובייקט david מועבר אליה.

אז מה קרה כאן בעצם?
בדוגמה הנ"ל ישנה פונקציה בשם sayHello, הפונקציה מדפיסה ל-console משפט הכולל בתוכו את ה-property בשם name של האובייקט שמועבר לפונקציה.
לאחר מכן, בשורה מספר 5, נוצר אובייקט פשוט בשם david עם ה-property בשם name כמובן והערך david מן הסתם.
בשורה האחרונה, על ידי שימוש במתודה call, בוצעה הוצאה אל הפועל של הפונקציה sayHello כאשר הארגומנט שהועבר אליה היה האובייקט david ולכן ה-this במקרה זה הצביע על האובייקט…david, ברור.

דוגמה נוספת:

let sayHello = function() {
    console.log('Hello! My name is ' + this.name);
}

let david = {
    name: 'David'
}

let maria = {
    name: 'Maria'
}

sayHello.call(maria);

במקרה הבא למשל, this מצביע על האובייקט בשם maria ולכן הפלט אל הקונסול יהיה:

הפלט שיוצא מהפונקציה sayHello כאשר האובייקט maria מועבר אליה.
הפלט שיוצא מהפונקציה sayHello כאשר האובייקט maria מועבר אליה.

ארגומנטים נוספים

ניתן להעביר גם ארגומנטים נוספים אל המתודה:

let sayHello = function(country) {
    console.log('Hello! My name is ' + this.name + ' and I\'m from ' + country);
}

let david = {
    name: 'David'
}

let maria = {
    name: 'Maria'
}

sayHello.call(maria, 'Italy');

הארגומנט הראשון תמיד יהיה האובייקט ש-this יצביע עליו ולאחר מכן יגיעו הפרמטרים שהפונקציה שבה נשתמש מצפה לקבל, במקרה זה, הפרמטר שהפונקציה sayHello מצפה לקבל הוא country והערך שלו הוא Italy כמובן.
הפלט:

הפלט שיוצא מהפונקציה sayHello כאשר האובייקט maria והארגומנט country מועברים אליה.
הפלט שיוצא מהפונקציה sayHello כאשר האובייקט maria והארגומנט country מועברים אליה.

שימוש במתודה שנמצאת באובייקט אחר

ניתן להשתמש במתודה call גם כאשר המתודה שנרצה להשתמש בה נמצאת באובייקט אחר לגמרי:

let david = {
    name: 'David',
    country: 'Germany',
    sayHello: function() {
        console.log('Hello! My name is ' + this.name + ' and I\'m from ' + this.country);
    }
};

let maria = {
    name: 'Maria',
    country: 'Italy'
};

david.sayHello.call(maria);

מה שקרה כאן זה שהאובייקט maria השתמש במתודה sayHello אשר קיימת באובייקט david בכלל, קולטים? 🙂
הפלט זהה לפלט מהדוגמה הקודמת.
חשוב לשים לב, כאשר משתמשים במתודה שקיימת באובייקט, אין לשכוח לציין את שם האובייקט לפני שם המתודה:

כאשר משתמשים במתודה שקיימת באובייקט, אין לשכוח לציין את שם האובייקט לפני שם המתודה.
כאשר משתמשים במתודה שקיימת באובייקט, אין לשכוח לציין את שם האובייקט לפני שם המתודה.

()apply

המתודה apply דומה מאוד למתודה call, ההבדל הוא שהמתודה apply מקבלת את הארגומנטים כמערך ולא באופן נפרד.
דוגמה:

let sayHello = function(age, country) {
    console.log('Hello! My name is ' + this.name + ', I\`m ' + age + ' years old and I\'m from ' + country);
}

let david = {
    name: 'David'
}

sayHello.apply(david, [29, 'Germany']);

בדוגמה הנ"ל המתודה sayHello מצפה לקבל 2 ארגומנטים, אבל מאחר ונעשה שימוש ב-apply ולא ב-call הארגומנטים יועברו כמערך ולא באופן מופרד.
הפלט:

הפלט שיוצא מהפונקציה sayHello כאשר הארגומנטים מועברים במערך.
הפלט שיוצא מהפונקציה sayHello כאשר הארגומנטים מועברים במערך.

()bind

אז מהי המתודה bind?
המתודה bind מאוד דומה למתודה call אך עם שינוי משמעותי אחד – היא לא מייצרת קריאה אל הפונקציה באופן מיידי.
דוגמה:

let sayHello = function(age, country) {
    console.log('Hello! My name is ' + this.name + ', I\`m ' + age + ' years old and I\'m from ' + country);
}

let david = {
    name: 'David'
}

let davidSayHello = sayHello.bind(david, 29, 'Germany');
davidSayHello();

הפלט יהיה זהה לפלט מהדוגמה הקודמת מאחר וחוץ ממועד ביצוע הפונקציה לא השתנה דבר.
חשוב לשים לב, בשורה מספר 9 המשתנה בשם davidSayHello מקבל לתוכו את הפונקציה.
הקריאה עצמה מתבצעת רק בשורה מספר 10.
שורה קצרה שתוכיח זאת:

console.log(davidSayHello);

והפלט שהתקבל:

ניתן לראות ש-davidSayHello מכיל בתוכו את הפונקציה.
ניתן לראות ש-davidSayHello מכיל בתוכו את הפונקציה.

ניתן לראות בבירור כי davidSayHello מכיל בתוכו אך ורק את הפונקציה עצמה, הקריאה עוד לא התבצעה בשלב זה.
המתודה bind מאפשרת גמישות שאין ב-call וה-apply, העובדה שהיא לא מבצעת קריאה לפונקציה באופן מיידי מאפשרת להשתמש בפונקציה במועד מאוחר יותר ואף מספר פעמים במידת הצורך.

בהצלחה!

נהנת ממאמר זה? הירשם לרשימת התפוצה וקבל עדכונים על מאמרים חדשים!


רק רגע! :)
כשאני לא כותב פוסטים ב-CodeBrain אני מספק שרותי פיתוח, ייעוץ והדרכה.
אם נראה לך שאני האיש המתאים עבורך, כדאי שנדבר :)

10 תגובות בנושא “על המתודות call, apply ו-bind ב-JavaScript”

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *