La parola chiave this
fa riferimento al valore dell'oggetto associato alla funzione al momento della sua chiamata, il che significa che il suo valore è diverso a seconda che una funzione venga chiamata come metodo, come funzione autonoma o come costruttore.
Quando una funzione viene chiamata, viene creata un'istanza della parola chiave this
dietro le quinte come riferimento all'oggetto che contiene la funzione, dando accesso alle proprietà e ai metodi definiti al suo interno dal suo ambito.
L'utilizzo di this
è in qualche modo simile all'utilizzo di una variabile dichiarata con const
. Come una costante, this
non può essere rimosso e il suo valore non può essere riassegnato, ma i metodi e le proprietà dell'oggetto contenuto dalla parola chiave this
possono essere modificati.
Vincolo globale
Al di fuori di una funzione o del contesto di un oggetto, this
fa riferimento alla proprietà globalThis
, che è un riferimento all'oggetto globale nella maggior parte degli ambienti JavaScript. Nel contesto di uno script in esecuzione in un browser web,
l'oggetto globale è l'oggetto window
:
this;
> Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, ...}
In Node.js, globalThis
è l'oggetto global
:
$ node
Welcome to Node.js v20.10.0.
Type ".help" for more information.
> this
<ref *1> Object [global] {
...
}
Al di fuori della modalità rigorosa, this
fa riferimento anche all'oggetto globale all'interno di una funzione autonoma, perché Window
principale è l'oggetto che "possiede" effettivamente queste funzioni.
function myFunction() {
console.log( this );
}
myFunction();
> Window {...}
(function() {
console.log( this );
}());
> Window {...}
Quando utilizzi la modalità rigorosa, this
ha un valore undefined
all'interno di una funzione autonoma:
(function() {
"use strict";
console.log( this );
}());
> undefined
Prima dell'introduzione della modalità rigorosa, un valore null
o undefined
per this
viene sostituito da un riferimento all'oggetto globale. A volte potresti vedere la associazione globale indicata come "associazione predefinita" a causa di questo comportamento precedente.
Associazione implicita
Quando una funzione viene chiamata come metodo di un oggetto, un'istanza di this
all'interno di quel metodo fa riferimento all'oggetto che contiene il metodo, dando accesso ai metodi e alle proprietà che si trovano accanto:
let myObject = {
myValue: "This is my string.",
myMethod() {
console.log( this.myValue );
}
};
myObject.myMethod();
> "This is my string."
Sembra che il valore di this
dipenda dal modo in cui sono definiti una funzione e il suo oggetto contenitore. Il contesto per il valore di this
è invece il contesto di esecuzione corrente. In questo caso, il contesto di esecuzione è che l'oggetto myObject
chiama il metodo myMethod
, quindi myObject
è il valore per this
. Questa potrebbe sembrare una formalità nel contesto degli esempi precedenti, ma per utilizzi più avanzati di this
è una distinzione essenziale da tenere presente.
In generale, utilizza this
in modo da non prevedere che il codice circostante abbia una struttura particolare. L'eccezione a questa regola sono le funzioni freccia ES5.
this
nelle funzioni con freccia
Nelle funzioni freccia,
this
si risolve in un'associazione in un
ambiente che lo racchiude in modo lessicale. Ciò significa che
this
in una funzione freccia si riferisce al valore di this
nel
contesto più esterno che la racchiude:
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 {...}
Nell'esempio precedente, myObject.myMethod()
registra myObject
come oggetto
che "possiede" il metodo, ma myObject.myArrowFunction()
restituisce globalThis
(o undefined
), perché l'istanza di this
all'interno della funzione freccia
si riferisce invece all'ambito più esterno.
Nel seguente esempio, myEnclosingMethod
crea una funzione freccia sull'oggetto che la contiene quando viene eseguita. L'istanza di this
all'interno della funzione freccia ora fa riferimento al valore di this
all'interno dell'ambiente di contenimento, ovvero il metodo che contiene la funzione freccia. Poiché il valore di this
all'interno di myEnclosingMethod
fa riferimento a myObject
, dopo aver definito la funzione freccia, this
all'interno della funzione freccia fa riferimento anche a myObject
:
let myObject = {
myMethod() { console.log( this ); },
myEnclosingMethod: function () {
this.myArrowFunction = () => { console.log(this) };
}
};
myObject.myEnclosingMethod();
myObject.myArrowFunction();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }
Vincolo esplicito
Il binding implicito gestisce la maggior parte dei casi d'uso per lavorare con this
. Tuttavia, a volte potresti dover utilizzare il valore this
per rappresentare un contesto di esecuzione specifico anziché quello presupposto. Un esempio illustrativo, anche se leggermente obsoleto, è l'utilizzo di this
all'interno della funzione di callback di un setTimeout
, poiché questo callback ha un contesto di esecuzione univoco:
var myObject = {
myString: "This is my string.",
myMethod() {
console.log( this.myString );
}
};
myObject.myMethod();
> "This is my string."
setTimeout( myObject.myMethod, 100 );
> undefined
Sebbene questo svantaggio specifico di setTimeout
sia stato risolto da altre funzionalità, problemi simili di "perdita" di this
sono stati risolti in precedenza creando un riferimento esplicito al valore di this
nell'ambito del contesto previsto. A volte potresti notare che istanze di this
vengono assegnate
a una variabile utilizzando identificatori come that
, self
o _this
nelle basi di codice legacy. Si tratta di convenzioni di identificatori comuni per le variabili contenenti un valore this
passato.
Quando chiami una funzione utilizzando i metodi call()
, bind()
o apply()
,
this
fa riferimento esplicito all'oggetto chiamato:
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."
Il binding esplicito sostituisce il valore this
fornito dal binding implicito.
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."
Se una funzione viene chiamata in modo da impostare il valore di this
su
undefined
o null
, questo valore viene sostituito da globalThis
al di fuori della modalità rigorosa:
let myFunction = function() {
console.log( this );
}
myFunction.call( null );
> Window {...}
Analogamente, se una funzione viene chiamata in modo da assegnare a this
un valore primitivo, questo valore viene sostituito con l'oggetto wrapper del valore primitivo al di fuori della modalità rigorosa:
let myFunction = function() {
console.log( this );
}
let myNumber = 10;
myFunction.call( myNumber );
> Number { 10 }
In modalità rigorosa, un valore this
passato non viene forzato in alcun modo in un oggetto, anche se si tratta di un valore primitivo, null
o undefined
:
"use strict";
let myFunction = function() {
console.log( this );
}
let myNumber = 10;
myFunction.call( myNumber );
> 10
myFunction.call( null );
> null
new
associazione
Quando una classe viene utilizzata come costruttore utilizzando la parola chiave new
, this
fa riferimento all'istanza appena creata:
class MyClass {
myString;
constructor() {
this.myString = "My string.";
}
logThis() {
console.log( this );
}
}
const thisClass = new MyClass();
thisClass.logThis();
> Object { myString: "My string." }
Analogamente, il valore di this
all'interno di una funzione di costruttore chiamata utilizzando new
si riferisce all'oggetto in fase di creazione:
function MyFunction() {
this.myString = "My string.";
this.logThis = function() {
console.log( this );
}
}
const myObject = new MyFunction();
myObject.logThis();
> Object { myString: "My string.", logThis: logThis() }
Collegamento del gestore di eventi
Nel contesto dei gestori degli eventi, il valore di this
fa riferimento all'oggetto che lo invoca. All'interno della funzione di callback di un gestore di eventi, this
fa riferimento all'elemento associato al gestore:
let button = document.querySelector( "button" );
button.addEventListener( "click", function( event ) { console.log( this ); } );
Quando un utente interagisce con button
nello snippet precedente, il risultato è
l'oggetto elemento contenente <button>
stesso:
> Button {}
Quando una funzione freccia viene utilizzata come callback del listener di eventi, il valore di
this
viene fornito di nuovo dal contesto di esecuzione più esterno. A livello superiore, this
all'interno di una funzione di callback del gestore eventi èglobalThis
:
let button = document.querySelector( "button" );
button.addEventListener( "click", ( event ) => { console.log( this ); } );
> undefined
Come per qualsiasi altro oggetto, quando utilizzi i metodi call()
, bind()
o apply()
per fare riferimento alla funzione di callback di un gestore di eventi, this
fa riferimento all'oggetto in modo esplicito:
let button = document.querySelector( "button" );
let myObject = {
"myValue" : true
};
function handleClick() {
console.log( this );
}
button.addEventListener( "click", handleClick.bind( myObject ) );
> Object { myValue: true }
Verificare di aver compreso
Per uno script in esecuzione in un browser web, qual è l'oggetto globale
a cui fa riferimento this
quando viene utilizzato al di fuori di una funzione o del
contesto di un oggetto?
window
browser
undefined