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

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

כשמפעילים את הפונקציה, היא יוצרת מאחורי הקלעים מופע של מילת המפתח 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, כי לקריאה חוזרת (callback) זו יש הקשר ייחודי של ביצוע:

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 מחוץ למצב strict:

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

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

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

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 משמש כבונה באמצעות מילת המפתח 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 בתוך פונקציה של מבנה שנקרא באמצעות 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 מפנה לאלמנט שמשויך ל-handler:

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

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

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

> Button {}

כשפונקציית חץ משמשת כקריאה חוזרת (callback) של event listener, הערך של this מסופק שוב לפי הקשר הביצוע המצורף הקרוב ביותר. ברמה העליונה, המשמעות היא ש-this בתוך פונקציית קריאה חוזרת של הגורם המטפל באירועים הוא globalThis (או undefined במצב מחמיר):

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

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

כמו בכל אובייקט אחר, כשמשתמשים בשיטות call(), bind() או apply() כדי להפנות לפונקציית הקריאה החוזרת של פונקציות event listener, 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