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