מילת המפתח 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