פרק 16: Function Context (הקשר הפונקציה) ב-JavaScript

1. מה זה Context (הקשר)?

Context (הקשר) בפונקציות ב-JavaScript מתייחס לערך של המילה השמורה this בתוך הפונקציה. הקשר קובע על איזה אובייקט פונקציה מופעלת ומי המאפיינים שהיא תוכל לגשת אליהם. ערך this תלוי בצורה שבה הפונקציה נקראת, ולא איפה היא הוגדרה.

2. הבנה בסיסית של this

ב-JavaScript, המילה השמורה this מתייחסת לאובייקט שבו הפונקציה פועלת כרגע. הקשר של this משתנה בהתאם לאיך הפונקציה נקראת.

דוגמה בסיסית:

const person = {
    name: "Alice",
    greet: function() {
        console.log("Hello, my name is " + this.name);
    }
};

person.greet(); // מציג "Hello, my name is Alice"

הסבר:

  • בתוך הפונקציה greet, המילה this מתייחסת לאובייקט person.
  • כאשר קוראים לפונקציה באמצעות person.greet(), this מצביע על האובייקט person, ולכן הפלט הוא "Hello, my name is Alice".

3. this בקונטקסט גלובלי

כאשר משתמשים ב-this מחוץ לפונקציה או בתוך פונקציה גלובלית (שאינה שייכת לאובייקט), this מתייחס לאובייקט הגלובלי (ב-דפדפן זה יהיה window).

דוגמה:

console.log(this); // בדפדפן זה יציג את האובייקט הגלובלי window

דוגמה בתוך פונקציה גלובלית:

function showThis() {
    console.log(this);
}

showThis(); // מציג את אובייקט window

הסבר:

  • כאשר לא מוגדר אובייקט ספציפי שבו הפונקציה מופעלת, this מתייחס לאובייקט הגלובלי (window בדפדפן או global ב-Node.js).

4. this באובייקטים

כאשר פונקציה מוגדרת כחלק מאובייקט (שיטה בתוך אובייקט), this מתייחס לאובייקט שבו הפונקציה מופעלת.

דוגמה:

const car = {
    brand: "Toyota",
    model: "Corolla",
    displayInfo: function() {
        console.log("Car: " + this.brand + " " + this.model);
    }
};

car.displayInfo(); // מציג "Car: Toyota Corolla"

הסבר:

  • הפונקציה displayInfo נמצאת בתוך האובייקט car, ולכן כאשר היא נקראת באמצעות car.displayInfo(), המילה this מתייחסת לאובייקט car.

5. this בתוך פונקציות חץ (Arrow Functions)

פונקציות חץ (Arrow Functions) מתנהגות בצורה שונה עם this. בפונקציות חץ, this נשאר זהה להקשר שבו הפונקציה נכתבה ולא משתנה לפי אופן הקריאה לפונקציה.

דוגמה:

const person = {
    name: "Bob",
    greet: function() {
        const innerGreet = () => {
            console.log("Hello, my name is " + this.name);
        };
        innerGreet();
    }
};

person.greet(); // מציג "Hello, my name is Bob"

הסבר:

  • הפונקציה innerGreet היא פונקציית חץ, ולכן this בתוכה נשאר מתייחס לאותו אובייקט שבו היא נכתבה, שהוא person במקרה הזה.
  • גם בתוך innerGreet, this.name מתייחס ל-person.name ומחזיר את השם "Bob".

דוגמה לפונקציה רגילה:

const person = {
    name: "Bob",
    greet: function() {
        function innerGreet() {
            console.log("Hello, my name is " + this.name);
        }
        innerGreet();
    }
};

person.greet(); // מציג "Hello, my name is undefined"

הסבר:

  • כאשר משתמשים בפונקציה רגילה בתוך פונקציה אחרת, this מתעדכן להקשר חדש (במקרה זה, האובייקט הגלובלי), ולכן this.name מחזיר undefined.

6. שימוש ב-bind, call, ו-apply לשינוי הקשר

ניתן לשנות את ערך this באופן ידני באמצעות שלוש פונקציות עזר: bind, call, ו-apply.

bind: קובע הקשר קבוע

bind יוצר גרסה חדשה של הפונקציה שבה this נקבע לערך מסוים, אך לא קורא לפונקציה מיד.

דוגמה:

const person = {
    name: "Alice",
};

function greet() {
    console.log("Hello, my name is " + this.name);
}

const greetPerson = greet.bind(person);
greetPerson(); // מציג "Hello, my name is Alice"

הסבר:

  • הפונקציה greet.bind(person) יוצרת פונקציה חדשה שבה this קבוע ומפנה ל-person.
  • כאשר קוראים ל-greetPerson(), הפונקציה מדפיסה את השם של person.

call: מפעיל את הפונקציה עם הקשר חדש

call מפעיל את הפונקציה באופן מיידי ומאפשר להעביר לה ערך של this וכן פרמטרים.

דוגמה:

const person = {
    name: "Bob",
};

function greet(greeting) {
    console.log(greeting + ", my name is " + this.name);
}

greet.call(person, "Hi"); // מציג "Hi, my name is Bob"

הסבר:

  • call מאפשר להפעיל את הפונקציה greet עם הקשר שבו this מצביע על האובייקט person ולשלוח את הפרמטרים לפונקציה.

apply: כמו call, אך עם מערך פרמטרים

apply דומה מאוד ל-call, אבל במקום להעביר פרמטרים אחד אחד, היא מקבלת מערך של פרמטרים.

דוגמה:

const person = {
    name: "Charlie",
};

function greet(greeting, punctuation) {
    console.log(greeting + ", my name is " + this.name + punctuation);
}

greet.apply(person, ["Hello", "!"]); // מציג "Hello, my name is Charlie!"

הסבר:

  • apply מפעילה את הפונקציה עם אותו הקשר כמו call, אבל מעבירה את הפרמטרים בתוך מערך.

7. דוגמה מלאה: שינוי הקשר עם פונקציות עזר

נבנה דוגמה שמשתמשת ב-bind, call, ו-apply כדי לשנות את ההקשר של הפונקציה.

const user1 = {
    name: "Alice",
};

const user2 = {
    name: "Bob",
};

function greet(greeting) {
    console.log(greeting + ", my name is " + this.name);
}

// שימוש ב-bind כדי ליצור פונקציה חדשה עם הקשר ל-user1
const greetAlice = greet.bind(user1);
greetAlice("Hello"); // מציג "Hello, my name is Alice"

// שימוש ב-call כדי להפעיל את הפונקציה עם הקשר ל-user2
greet.call(user2, "Hi"); // מציג "Hi, my name is Bob"

// שימוש ב-apply כדי להפעיל את הפונקציה עם הקשר ל-user1 ולשלוח פרמטרים כמערך
greet.apply(user1, ["Hey"]); // מציג "Hey, my name is Alice"

הסבר:

  • בעזרת bind יצרנו פונקציה חדשה שההקשר שלה הוא user1.
  • עם call, הפעלנו את הפונקציה עם הקשר שונה (user2).
  • עם apply, השתמשנו במערך פרמטרים להעברת נתונים לפונקציה.

8. סיכום ההבדלים בין פונקציות רגילות ל-Arrow Functions

  • פונקציות רגילות: ערך this משתנה בהתאם לאופן הקריאה לפונקציה. ניתן לשנות אותו עם bind, call, ו-apply.
  • פונקציות חץ (Arrow Functions): ערך this נלקח מההקשר שבו הפונקציה נכתבה, והוא לא משתנה בעת הקריאה לפונקציה.

סיכום

בפרק זה למדנו על:

  1. מהו ההקשר (this) בפונקציות ב-JavaScript ואיך הוא משתנה בהתאם לצורת הקריאה לפונקציה.
  2. ההבדלים בין this בפונקציות רגילות לבין this בפונקציות חץ.
  3. שימוש ב-bind, call, ו-apply לשינוי הקשר הפונקציה באופן ידני.
  4. דוגמאות שונות לשימוש בהקשר הפונקציה בסביבות שונות כמו אובייקטים, פונקציות גלובליות ופונקציות חץ.

בפרק הבא נעמיק בנושא Inheritance (ירושה) ונראה כיצד להרחיב מחלקות וירושה בין מחלקות ב-JavaScript.

Scroll to Top
דילוג לתוכן