Menu

Arrow function in JavaScript: =>, this e quando usarle

Come funzionano le arrow function in JavaScript: la sintassi =>, il return implicito, come gestiscono this e quando conviene usarle al posto di function.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Un modo più breve di scrivere una funzione

Le arrow function sono la sintassi più compatta di JavaScript per definire una funzione. Sono arrivate con ES2015 e oggi sono lo stile predefinito per le funzioni piccole e inline, soprattutto le callback passate ai metodi degli array, gli handler delle promise e gli event listener.

La forma è: parametri, poi =>, poi il corpo.

Stesso risultato della forma classica:

const add = function (a, b) {
    return a + b;
};

Scrivere meno è comodo, ma i veri motivi per interessarsi alle arrow function sono il return implicito e il modo in cui trattano this. Li vediamo tra poco.

Return implicito

Se il corpo è una singola espressione, puoi togliere le graffe e il return. Il valore dell'espressione viene restituito automaticamente:

È qui che le arrow function danno il meglio: le trasformazioni di una riga si leggono come formule matematiche:

Appena ti serve più di un'istruzione, tornano le graffe e un return esplicito:

Dimenticare il return dentro le graffe è l'errore più comune con le arrow function. x => { x * 2 } restituisce undefined: le graffe trasformano il corpo in un blocco e l'espressione al suo interno viene scartata.

Parentesi dei parametri

Con un solo parametro, le parentesi sono facoltative:

Con zero, due o più parametri, sono obbligatorie:

Alcuni team preferiscono usare sempre le parentesi per coerenza. Vanno bene entrambi gli stili: scegline uno e mantienilo.

Restituire un oggetto letterale

Ecco un tranello. Se provi a restituire implicitamente un oggetto, le graffe sembrano il corpo di una funzione:

Questo stampa undefined. JavaScript legge { name: name } come un blocco con un'istruzione etichettata, non come un oggetto letterale. Racchiudi l'oggetto tra parentesi per forzarlo a essere un'espressione:

Le () attorno a { ... } sono la soluzione. Tienilo a mente: ci sbatterai contro entro la prima settimana di arrow function.

this lessicale

Il vero motivo per cui esistono le arrow function non è la sintassi più breve. È che non hanno un proprio this: lo ereditano dallo scope circostante.

Per capire perché conta, guarda una funzione normale usata come callback:

Dentro la function () { ... } passata a setInterval, this non è counter. Le funzioni normali ricevono un proprio this in base a come vengono chiamate, e setInterval chiama la callback con this uguale a undefined (in strict mode) oppure all'oggetto globale.

Una arrow function mantiene il this del metodo che la contiene:

Dentro la arrow function, this è ancora counter perché la freccia non introduce un proprio this. Prima delle arrow function si aggirava il problema con const self = this; o .bind(this). Questi pattern funzionano ancora, ma oggi servono di rado.

Cosa non hanno le arrow function

La regola del this lessicale fa parte di uno schema più ampio: le arrow function rinunciano a diverse cose che le funzioni normali hanno.

  • Nessun this proprio: viene ereditato dallo scope esterno.
  • Nessun oggetto arguments: usa invece i parametri rest (...args).
  • Niente new: non puoi usare una arrow function come costruttore.
  • Nessuna proprietà prototype: è una conseguenza della regola sul new.

...args ti dà la stessa possibilità di "accettare un numero qualsiasi di argomenti" che dava arguments, con il vantaggio che è un vero array. La chiamata new Greeter(...) genera un errore perché le arrow function non sono costruttori.

Quando non usare una arrow function

Le arrow function sono la scelta predefinita per le callback, ma in alcuni casi sono la scelta sbagliata:

I metodi di un oggetto definiti con la sintassi a freccia non hanno this legato all'oggetto: lo ereditano dal punto in cui è stato scritto l'oggetto letterale (di solito lo scope del modulo o quello globale). Per i metodi usa la sintassi abbreviata (greet() { ... }).

Lo stesso vale per i metodi del prototype di una classe, per i metodi usati come event handler che hanno bisogno che this sia l'elemento, e per qualsiasi funzione che vuoi chiamare con new. Lì lo strumento giusto è una function normale.

Una regola pratica veloce

  • Callback breve, una sola espressione? Arrow function.
  • Ti serve che this resti legato allo scope esterno? Arrow function.
  • Stai definendo un metodo su un oggetto o sul prototype di una classe? Funzione normale (o metodo abbreviato).
  • Stai scrivendo un costruttore? Funzione normale, o meglio ancora una class.

In qualsiasi codebase JavaScript reale vedrai entrambi gli stili. Per capire quale si adatta meglio bastano poche settimane passate a leggere il codice degli altri: dopo, la scelta diventa automatica.

Prossimo passo: parametri e valori predefiniti

Arrow function e funzioni normali condividono le stesse funzionalità per i parametri: valori predefiniti, parametri rest, argomenti destrutturati e altro. È l'argomento della prossima pagina, e vale per tutte le forme di funzione viste finora.

Domande frequenti

Cos'è una arrow function in JavaScript?

Una arrow function (o funzione freccia) è un modo più breve di scrivere una funzione, con la sintassi =>. const add = (a, b) => a + b; è una arrow function che riceve due argomenti e ne restituisce la somma. Oltre alla sintassi più compatta, le arrow function non hanno un proprio this, né arguments, né super: li ereditano dallo scope circostante.

Che differenza c'è tra arrow function e funzioni normali?

Le funzioni dichiarate con function hanno un proprio this, un proprio oggetto arguments e possono essere usate come costruttori con new. Le arrow function non hanno niente di tutto questo: ereditano this dal punto in cui sono definite. Inoltre le arrow function non subiscono l'hoisting come le dichiarazioni di funzione.

Quando conviene usare una arrow function?

Usale per le callback brevi (arr.map(x => x * 2)) e ovunque tu voglia che this resti legato allo scope esterno, per esempio dentro un metodo di classe che passa un handler a setTimeout o a un event listener. Usa una function normale per i metodi degli oggetti, i costruttori e le funzioni autonome di primo livello.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA