JavaScript, come linguaggio di programmazione versatile e potente, presenta numerosi concetti unici e interessanti. Uno di questi è la variabile this
, che rappresenta uno degli aspetti più intriganti e talvolta confondenti di JavaScript. Comprendere this
è essenziale per qualsiasi sviluppatore che desidera padroneggiare JavaScript, dato il suo ruolo cruciale nella scrittura di codice efficiente e nella comprensione del funzionamento interno del linguaggio.
Cos’è this in JavaScript?
La variabile this
in JavaScript è un riferimento al contesto di esecuzione corrente. È importante notare che il valore di this
non è fisso, ma cambia a seconda di come e dove viene chiamata una funzione.
In termini semplici, this
si riferisce all'oggetto che sta "eseguendo" il codice corrente. Può riferirsi a diversi oggetti a seconda del contesto, come l'oggetto globale, l'oggetto di una classe, o l'oggetto che ha invocato una funzione.
this
quindi cambia il suo valore in base al contesto dove si trova, ad esempio:
Nel contesto globale: In un contesto non strettamente definito (non in strict mode), this
si riferisce all'oggetto globale, che è window
nel browser e global
in Node.js.
1 console.log(this === window); // true in un browser
All'interno di una funzione: Il valore di this
all'interno di una funzione dipende da come la funzione viene chiamata. Se una funzione regolare è chiamata globalmente, this
si riferisce ancora all'oggetto globale. In strict mode, tuttavia, this
sarà undefined
.
1 function mostraThis() {
2 console.log(this);
3 }
4 mostraThis(); // 'window' in non-strict mode, 'undefined' in strict mode
Metodi di oggetti: Quando this
è usato all'interno di un metodo di un oggetto, si riferisce all'oggetto che contiene il metodo.
1 const oggetto = {
2 metodo: function() {
3 console.log(this);
4 }
5 };
6 oggetto.metodo(); // Logga `oggetto`
Confronto con Altri Linguaggi di Programmazione
In altri linguaggi di programmazione, come Java o C++, this
ha un significato più statico e prevedibile, in quanto si riferisce sempre all'istanza della classe corrente. In JavaScript, tuttavia, a causa del suo modello di esecuzione basato su funzioni e della natura dinamica del linguaggio, this
può avere significati diversi in base al contesto di chiamata.
this
nelle arrow function e nelle funzioni regolari
Le funzioni regolari in JavaScript hanno un comportamento dinamico rispetto a this
. Il valore di this
all'interno di una funzione regolare dipende da come la funzione è chiamata, non da dove è definita.
Chiamata Diretta: Se una funzione regolare viene chiamata direttamente (ad esempio, funzione()
), this
fa riferimento all'oggetto globale (window
in un browser, global
in Node.js). In strict mode, this
sarà undefined
.
1 function funzioneRegolare() {
2 console.log(this);
3 }
4 funzioneRegolare(); // `window` in browser, `undefined` in strict mode
Come Metodo di un Oggetto: Se la funzione è un metodo di un oggetto, this
si riferisce all'oggetto che contiene il metodo.
1 const oggetto = {
2 metodoRegolare: function() {
3 console.log(this);
4 }
5 };
6 oggetto.metodoRegolare(); // Logga `oggetto`
Arrow function
Le arrow function, introdotte in ES6, hanno un comportamento di this
"lessicale". Ciò significa che this
all'interno di una funzione arrow è sempre uguale a this
nel contesto del codice circostante (dove la funzione è definita), indipendentemente da come la funzione è chiamata.
Ereditarietà Lessicale: Le funzioni arrow ereditano this
dal loro contesto di definizione. Non hanno un proprio this
.
1 const oggetto = {
2 metodoRegolare: function() {
3 const funzioneArrow = () => console.log(this);
4 funzioneArrow();
5 }
6 };
7 oggetto.metodoRegolare(); // Logga `oggetto`
In questo esempio, la funzioneArrow
eredita this
dal metodoRegolare
.
Confronto e scenari di utilizzo
Preferire funzioni arrow per ereditare this
: Le funzioni arrow sono utili quando si desidera mantenere il contesto di this
dallo scope circostante, come in callback o in metodi definiti all'interno di altri metodi.
Usare funzioni regolari per un this
dinamico: Le funzioni regolari sono più appropriate quando si ha bisogno che this
faccia riferimento al contesto in cui la funzione è stata chiamata, come nei metodi degli oggetti.
Binding Esplicito di this
In JavaScript, è possibile impostare o "legare" esplicitamente il valore di this
in una funzione. Questo si ottiene principalmente tramite tre metodi: .bind()
, .call()
, e .apply()
.
Metodo .bind()
Il metodo .bind()
crea una nuova funzione che, quando viene chiamata, ha il suo this
impostato al valore fornito. È utile per assicurarsi che this
all'interno di una funzione sia legato a un oggetto specifico.
Esempio di .bind()
:
1 const oggetto = {
2 valore: 'Oggetto Originale',
3 };
4
5 function mostraThis() {
6 console.log(this.valore);
7 }
8
9 const legata = mostraThis.bind(oggetto);
10 legata(); // Logga 'Oggetto Originale'
In questo esempio, la funzione mostraThis
viene legata a oggetto
tramite .bind()
, quindi quando legata
viene chiamata, this
si riferisce a oggetto
.
Metodo .call()
Il metodo .call()
chiama una funzione con un valore di this
specificato e argomenti forniti individualmente. È utile per invocare una funzione e impostare esplicitamente il suo contesto this
.
Esempio di .call()
:
1 function saluta(nome) {
2 console.log(`Ciao, ${nome}. Io sono ${this.valore}`);
3 }
4
5 const oggetto = {
6 valore: 'Oggetto con Call',
7 };
8
9 saluta.call(oggetto, 'Mario'); // Logga 'Ciao, Mario. Io sono Oggetto con Call'
Qui, saluta
viene chiamata con this
impostato su oggetto
e l'argomento 'Mario'
.
Metodo .apply()
Il metodo .apply()
è simile a .call()
, ma gli argomenti sono passati come un array, non singolarmente. È utile quando non si conosce il numero di argomenti in anticipo.
Esempio di .apply()
:
1 function somma(a, b) {
2 console.log(a + b + this.extra);
3 }
4
5 const oggetto = {
6 extra: 5,
7 };
8
9 somma.apply(oggetto, [1, 2]); // Logga 8 (1 + 2 + 5)
Qui, somma
viene chiamata con this
impostato su oggetto
, e gli argomenti [1, 2]
.
Casi speciali e problemi comuni con this
Uno dei problemi più comuni nell'uso di this
in JavaScript è la "perdita" del contesto. Questo avviene tipicamente quando una funzione che fa uso di this
viene passata come callback.
Esempio di Perdita di Contesto:
1 const oggetto = {
2 nome: "Oggetto",
3 mostraNome: function() {
4 console.log(this.nome);
5 }
6 };
7
8 setTimeout(oggetto.mostraNome, 1000); // Logga 'undefined' invece di 'Oggetto'
In questo caso, la funzione mostraNome
perde il suo contesto originale quando viene passata a setTimeout
. this
all'interno di mostraNome
non si riferisce più a oggetto
.
Uso di arrow functions per mantenere il contesto
Le funzioni arrow possono essere utilizzate per evitare la perdita di contesto, poiché catturano il valore di this
dallo scope circostante al momento della loro definizione.
Esempio con Funzione Arrow:
1 const oggetto = {
2 nome: "Oggetto",
3 mostraNome: function() {
4 setTimeout(() => console.log(this.nome), 1000);
5 }
6 };
7
8 oggetto.mostraNome(); // Logga correttamente 'Oggetto'
Qui, la funzione arrow all'interno di setTimeout
mantiene il contesto this
originale di oggetto
.
this
in Event Listeners
Un'altra trappola comune si verifica con this
negli event listeners. this
all'interno di un listener si riferisce all'elemento che ha attivato l'evento, non all'oggetto che definisce il listener.
Esempio con Event Listener:
1 const oggetto = {
2 nome: "Oggetto",
3 init: function() {
4 document.addEventListener('click', function() {
5 console.log(this); // Si riferisce all'elemento `document`, non a `oggetto`
6 });
7 }
8 };
Per mantenere il contesto, si può utilizzare una funzione arrow o legare esplicitamente il contesto con .bind()
.
Uso di this
in costruttori e classi
Nei costruttori e nelle classi, this
si riferisce all'istanza dell'oggetto che viene creata. Tuttavia, se si dimentica di usare new
con un costruttore, this
può riferirsi inaspettatamente all'oggetto globale (o essere undefined
in strict mode).
Esempio con Costruttore:
Il seguente esempio include l'uso di this
in un contesto globale, all'interno di una funzione regolare, in un metodo di oggetto, e in una funzione arrow all'interno di un metodo di oggetto.
1// Contesto Globale
2console.log(this); // `this` si riferisce all'oggetto globale (es. `window` in un browser)
3
4// Funzione Regolare
5function mostraThisFunzione() {
6 console.log(this);
7}
8mostraThisFunzione(); // `this` si riferisce all'oggetto globale o `undefined` in strict mode
9
10// Oggetto con Metodo
11const oggetto = {
12 prop: "Valore Proprietà",
13 metodo: function() {
14 console.log(this.prop); // `this` si riferisce a `oggetto`
15
16 // Funzione Arrow all'interno di un Metodo
17 const funzioneArrow = () => {
18 console.log(this.prop); // `this` qui eredita il contesto da `metodo`, quindi si riferisce ancora a `oggetto`
19 };
20 funzioneArrow();
21 }
22};
23
24oggetto.metodo();
25
26// Funzione Costruttore
27function Costruttore(valore) {
28 this.valore = valore;
29}
30
31const istanza = new Costruttore("Mio Valore");
32console.log(istanza.valore); // `this` all'interno del costruttore si riferisce a `istanza`
- Contesto Globale: Viene mostrato come
this
si riferisca all'oggetto globale. - Funzione Regolare: Qui,
this
all'interno di una funzione regolare si riferisce all'oggetto globale o èundefined
se in strict mode. - Metodo di Oggetto: In un metodo di oggetto,
this
si riferisce all'oggetto che contiene il metodo. - Funzione Arrow in Metodo: All'interno del metodo, una funzione arrow dimostra come essa erediti
this
dal suo contesto circostante. - Funzione Costruttore: Un esempio di come
this
in una funzione costruttore si riferisce all'istanza dell'oggetto creato.
Caricamento...
Diventiamo amici di penna? ✒️
Iscriviti alla newsletter per ricevere una mail ogni paio di settimane con le ultime novità, gli ultimi approfondimenti e gli ultimi corsi gratuiti puubblicati. Ogni tanto potrei scrivere qualcosa di commerciale, ma solo se mi autorizzi, altrimenti non ti disturberò oltre.
Se non ti piace la newsletter ti ricordo la community su Discord, dove puoi chiedere aiuto, fare domande e condividere le tue esperienze (ma soprattutto scambiare due meme con me). Ti aspetto!