מילת המפתח הזו

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

כשפונקציה מופעלת, היא יוצרת מאחורי הקלעים מופע של מילת המפתח this כהפניה לאובייקט שמכיל את הפונקציה הזו, ומספקת גישה למאפיינים ולשיטות שהוגדרו לצד הפונקציה הזו מתוך ההיקף שלה. העבודה עם this דומה במובנים מסוימים לעבודה עם משתנה שמוצהר באמצעות const. כמו קבוע, אי אפשר להסיר את this ולא ניתן להקצות מחדש את הערך שלו, אבל אפשר לשנות את השיטות והמאפיינים של האובייקט שמכילה מילת המפתח this.

קישור גלובלי

מחוץ לפונקציה או להקשר של אובייקט, הערך this מתייחס למאפיין globalThis, שהוא הפניה לאובייקט הגלובלי ברוב סביבות JavaScript. בהקשר של סקריפט שפועל בדפדפן אינטרנט, האובייקט הגלובלי הוא האובייקט window:

this;
> Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, ...}

ב-Node.js, globalThis הוא האובייקט global:

$ node
Welcome to Node.js v20.10.0.
Type ".help" for more information.
> this
<ref *1> Object [global] {
...
}

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

function myFunction() {
    console.log( this );
}
myFunction();
> Window {...}

(function() {
    console.log( this );
}());
> Window {...}

כשמשתמשים במצב קפדני, הערך של this הוא undefined בתוך פונקציה עצמאית:

(function() {
    "use strict";
    console.log( this );
}());
> undefined

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

קישור מרומז

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

let myObject = {
    myValue: "This is my string.",
    myMethod() {
            console.log( this.myValue );
    }
};

myObject.myMethod();
> "This is my string."

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

באופן כללי, מומלץ להשתמש ב-this בדרכים שלא מחייבות מבנה ספציפי של הקוד שמקיף אותו. היוצא מן הכלל הוא פונקציות חץ ב-ES5.

this בפונקציות החץ

בפונקציות חץ, הערך של this מטופל כקישור בסביבה לוקלית מוחצת. כלומר, הערך של this בפונקציית החץ מתייחס לערך של this בהקשר הסגור הקרוב ביותר של הפונקציה:

let myObject = {
    myMethod() { console.log( this ); },
    myArrowFunction: () => console.log( this ),
    myEnclosingMethod: function () {
        this.myArrowFunction = () => { console.log(this) };
    }
};

myObject.myMethod();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }

myObject.myArrowFunction();
> Window {...}

בדוגמה הקודמת, myObject.myMethod() מתעדת את myObject כאובייקט ש'בעלים' של השיטה, אבל myObject.myArrowFunction() מחזירה את globalThis (או undefined), כי המופע של this בתוך פונקציית החץ מתייחס במקום זאת להיקף המקיף הגבוה ביותר.

בדוגמה הבאה, myEnclosingMethod יוצר פונקציית חץ באובייקט שמכיל אותו כשהיא מופעלת. המופע של this בתוך פונקציית החץ מתייחס עכשיו לערך של this בסביבה המקיפה, שהיא השיטה שמכילה את פונקציית החץ. מכיוון שהערך של this בתוך myEnclosingMethod מתייחס ל-myObject, אחרי שמגדירים את פונקציית החץ, הערך של this בתוך פונקציית החץ מתייחס גם ל-myObject:

let myObject = {
    myMethod() { console.log( this ); },
    myEnclosingMethod: function () {
        this.myArrowFunction = () => { console.log(this) };
    }
};

myObject.myEnclosingMethod();
myObject.myArrowFunction();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }

קישור מפורש

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

var myObject = {
  myString: "This is my string.",
  myMethod() {
    console.log( this.myString );
  }
};
myObject.myMethod();
> "This is my string."

setTimeout( myObject.myMethod, 100 );
> undefined

אמנם הבעיה הספציפית הזו ב-setTimeout טופלה מאז באמצעות תכונות אחרות, אבל בעיות דומות של 'אובדן' של this טופלו בעבר על ידי יצירה של הפניה מפורשת לערך של this בהיקף ההקשר המיועד. יכול להיות שתראו מדי פעם מקרים שבהם this מוקצה למשתנה באמצעות מזהים כמו that,‏ self או _this בבסיס קוד קודם. אלה מוסכמות נפוצות למזהים של משתנים שמכילים ערך this שהוענק.

כשקוראים לפונקציה באמצעות השיטות call(),‏ bind() או apply(), ‏this מפנה באופן מפורש לאובייקט שאליו קוראים:

let myFunction = function() {
    console.log( this.myValue );
}

let myObject = {
   "myValue" : "This is my string."
 };

myFunction.call( myObject );
> "This is my string."
var myObject = {
  myString: "This is my string.",
  myMethod() {
    console.log( this.myString );
  }
};

setTimeout( myObject.myMethod.bind( myObject ), 100 );
> "This is my string."

קישור מפורש מבטל את הערך של this שסופק על ידי קישור מרומז.

let myObject = {
    "myValue" : "This string sits alongside myMethod.",
    myMethod() {
        console.log( this.myValue );
    }
};
let myOtherObject = {
    "myValue" : "This is a string in another object entirely.",
};

myObject.myMethod.call( myOtherObject );
> "This is a string in another object entirely."

אם פונקציה נקראת באופן שיגדיר את הערך של this לערך undefined או null, הערך הזה מוחלף ב-globalThis מחוץ למצב קפדני:

let myFunction = function() {
    console.log( this );
}

myFunction.call( null );
> Window {...}

באופן דומה, אם קוראים לפונקציה באופן שיגרום להקצאת ערך פרימיטיבי ל-this, הערך הזה מוחלף באובייקט העטיפה של הערך הפרימיטיבי מחוץ למצב קפדני:

let myFunction = function() {
    console.log( this );
}

let myNumber = 10;

myFunction.call( myNumber );
> Number { 10 }

במצב קפדני, ערך this שהוענק לא הופך לאובייקט בשום צורה, גם אם הוא ערך פרימיטיבי, ערך null או ערך undefined:

"use strict";
let myFunction = function() {
    console.log( this );
}

let myNumber = 10;

myFunction.call( myNumber );
> 10

myFunction.call( null );
> null

קישור new

כשמשתמשים בclass כ-constructor באמצעות מילת המפתח new, הערך של this מתייחס למכונה שנוצרה לאחרונה:

class MyClass {
    myString;
    constructor() {
        this.myString = "My string.";
    }
    logThis() {
        console.log( this );
    }
}
const thisClass = new MyClass();

thisClass.logThis();
> Object { myString: "My string." }

באופן דומה, הערך של this בתוך פונקציית ה-constructor שנקראת באמצעות new מתייחס לאובייקט שנוצר:

function MyFunction() {
  this.myString = "My string.";
  this.logThis = function() {
    console.log( this );
  }
}
const myObject = new MyFunction();

myObject.logThis();
> Object { myString: "My string.", logThis: logThis() }

קישור של גורם מטפל באירועים

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

let button = document.querySelector( "button" );

button.addEventListener( "click", function( event ) { console.log( this ); } );

כשמשתמש מקיים אינטראקציה עם ה-button בקטע הקוד הקודם, התוצאה היא אובייקט האלמנט שמכיל את ה-<button> עצמו:

> Button {}

כשמשתמשים בפונקציית חץ כקריאה חוזרת של מאזין אירועים, הערך של this מסופק שוב על ידי הקשר הביצוע המקיף הקרוב ביותר. ברמה העליונה, המשמעות היא ש-this בתוך פונקציית קריאה חוזרת של טיפול באירוע היא globalThis:

let button = document.querySelector( "button" );

button.addEventListener( "click", ( event ) => { console.log( this ); } );
> undefined

כמו בכל אובייקט אחר, כשמשתמשים בשיטות call(),‏ bind() או apply() כדי להפנות לפונקציית הקריאה החוזרת של מאזין אירועים, this מפנה לאובייקט באופן מפורש:

let button = document.querySelector( "button" );
let myObject = {
    "myValue" : true
};
function handleClick() {
    console.log( this );
}

button.addEventListener( "click", handleClick.bind( myObject ) );
> Object { myValue: true }

בדיקת ההבנה

בסקריפט שפועל בדפדפן אינטרנט, מהו האובייקט הגלובלי ש-this מתייחס אליו כשמשתמשים בו מחוץ לפונקציה או מהקשר של אובייקט?

האובייקט window
האובייקט browser
האובייקט undefined