Il valore di questa parola chiave

La parola chiave this si riferisce al valore dell'oggetto associato alla funzione al momento della chiamata, il che significa che il suo valore è diverso a seconda che la funzione venga chiamata come metodo, come funzione autonoma o come costruttore.

Quando una funzione viene chiamata, questa crea 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 insieme ad essa dall'ambito del suo ambito. L'utilizzo di this è simile sotto alcuni aspetti rispetto all'uso di una variabile dichiarata con const. Come nel caso di una costante, this non può essere rimosso e il suo valore non può essere riassegnato, ma i metodi e le proprietà dell'oggetto contenente la parola chiave this possono essere modificati.

Associazione 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 eseguito 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à rigida, this si riferisce anche all'oggetto globale all'interno di una funzione autonoma, perché l'oggetto principale Window è l'oggetto che "possiede" effettivamente queste funzioni.

function myFunction() {
    console.log( this );
}
myFunction();
> Window {...}

(function() {
    console.log( this );
}());
> Window {...}

Quando utilizzi la modalità restrittiva, 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 veniva sostituito da un riferimento all'oggetto globale. A volte potresti vedere l'associazione globale definita "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 questo metodo fa riferimento all'oggetto che contiene il metodo, dando accesso ai metodi e alle proprietà associati:

let myObject = {
    myValue: "This is my string.",
    myMethod() {
            console.log( this.myValue );
    }
};

myObject.myMethod();
> "This is my string."

Potrebbe sembrare che il valore di this dipenda da come sono definiti una funzione e l'oggetto che lo contiene. Invece, il contesto per il valore di this è l'attuale contesto di esecuzione. In questo caso, il contesto di esecuzione indica che l'oggetto myObject chiama il metodo myMethod, quindi myObject è il valore di this. Potrebbe sembrare un aspetto tecnico nel contesto degli esempi precedenti, ma per usi più avanzati di this è una distinzione essenziale da tenere a mente.

In generale, utilizza this in modi che non si aspettano che il codice circostante abbia una struttura particolare. L'eccezione a questa regola è rappresentata dalle funzioni a freccia ES5.

this in funzioni freccia

Nelle funzioni a freccia, this si risolve in un'associazione in un ambiente circostante. Ciò significa che this in una funzione freccia fa riferimento al valore di this nel contesto più vicino di quella funzione:

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 l'oggetto "possiede" quel metodo, ma myObject.myArrowFunction() restituisce globalThis (o undefined), perché l'istanza di this all'interno della funzione freccia fa riferimento invece all'ambito di inclusione più alto.

Nell'esempio seguente, myEnclosingMethod crea una funzione freccia sull'oggetto che la contiene quando viene eseguito. L'istanza di this all'interno della funzione freccia ora fa riferimento al valore di this all'interno dell'ambiente che le include, ovvero il metodo che contiene la funzione freccia. Poiché il valore di this in 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() }

Associazione esplicita

L'associazione implicita gestisce la maggior parte dei casi d'uso per l'uso di this. Tuttavia, a volte potrebbe essere necessario il valore di this per rappresentare un contesto di esecuzione specifico, anziché il contesto presunto. Un esempio illustrativo, anche se leggermente obsoleto, funziona con this nella funzione di callback di un setTimeout, perché 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 difetto specifico di setTimeout sia stato risolto da altre funzionalità, problemi simili di "perdere" this sono stati precedentemente risolti creando un riferimento esplicito al valore di this nell'ambito del contesto previsto. A volte potresti notare che le istanze this vengono assegnate a una variabile utilizzando identificatori come that, self o _this nei codebase legacy. Queste sono convenzioni comuni per gli identificatori 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 che viene 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."

L'associazione esplicita sostituisce il valore this fornito dall'associazione implicita.

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 un modo che imposti il valore di this su undefined o null, tale valore viene sostituito da globalThis al di fuori della modalità restrittiva:

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

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

Analogamente, se una funzione viene chiamata in un modo che dia a this un valore primitivo, questo valore viene sostituito con l'oggetto wrapper del valore primitivo al di fuori della modalità restricted:

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

let myNumber = 10;

myFunction.call( myNumber );
> Number { 10 }

In modalità restrittiva, un valore this passato non viene forzato in alcun modo a 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

Associazione di new

Quando viene utilizzata una classe come costruttore con la parola chiave new, this si riferisce 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." }

Allo stesso modo, il valore di this all'interno di una funzione del costruttore chiamata utilizzando new fa riferimento all'oggetto che viene creato:

function MyFunction() {
  this.myString = "My string.";
  this.logThis = function() {
    console.log( this );
  }
}
const myObject = new MyFunction();

myObject.logThis();
> Object { myString: "My string.", logThis: logThis() }

Associazione gestore di eventi

Nel contesto dei gestori di eventi, il valore di this fa riferimento all'oggetto che lo richiama. 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 lo stesso <button>:

> Button {}

Quando una funzione freccia viene utilizzata come callback del listener di eventi, il valore di this viene nuovamente fornito dal contesto di esecuzione più vicino. Al livello principale, significa che this all'interno di una funzione di callback del gestore di eventi è globalThis (o undefined, in modalità con restrizioni):

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 listener 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 }

Verifica le tue conoscenze

Per uno script eseguito in un browser web, qual è l'oggetto globale a cui this fa riferimento se utilizzato al di fuori di una funzione o nel contesto di un oggetto?

L'oggetto window
L'oggetto browser
L'oggetto undefined