Il valore di questa parola chiave

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?

Oggetto window
Oggetto browser
Oggetto undefined