Oggetto Function di JavaScript ed Espressioni di Funzione con Nome (NFE)
Le funzioni JavaScript sono object: leggi le proprietà name e length, aggiungi proprietà personalizzate e usa le Named Function Expression (NFE) per la ricorsione.
Le funzioni sono object
In JavaScript, ogni funzione è un object. Questo singolo fatto spiega molti comportamenti che altrimenti sembrerebbero magia: puoi passare una funzione come qualsiasi valore, memorizzarla in una variabile, leggere proprietà da essa e persino aggiungere le tue proprietà.
Crei già funzioni continuamente con dichiarazioni ed espressioni di funzione. Questo capitolo analizza cos'è una funzione una volta creata: un object con utili proprietà built-in (name e length), la capacità di contenere proprietà personalizzate e una forma speciale — la Named Function Expression — che consente a una funzione di riferirsi a se stessa in modo affidabile.
Questa pagina presuppone che tu abbia familiarità con le Function Expression. Se let f = function() {...} è una novità per te, leggila prima.
La proprietà name
Ogni funzione ha una proprietà name che contiene il nome della funzione come string. La parte interessante è che JavaScript la compila anche quando non c'è un nome nel punto ovvio — un comportamento chiamato denominazione contestuale.
Il motore guarda l'assegnazione e copia il nome della variabile sulla funzione anonima. Questo funziona anche per i parametri predefiniti e i metodi degli object:
Non c'è magia che funzioni sempre, però. Se non c'è un nome e nulla da cui copiarne uno — ad esempio una funzione creata all'interno di un array — name è una string vuota:
La proprietà name è utile per il logging e il debugging: una stack trace che dice at sayHi è molto più utile di at <anonymous>.
La proprietà length
La proprietà length di una funzione restituisce il numero di parametri dichiarati nella sua definizione. I parametri rest (...rest) e i parametri con valori predefiniti non vengono contati, e il conteggio si interrompe al primo di tali parametri.
Un utilizzo comune di length è quello di esaminare una callback. Alcune librerie chiamano un handler in modo diverso a seconda di quanti argomenti si aspetta — ad esempio, trattando un handler senza argomenti come "esegui una volta per tutti" e un handler con un argomento come "esegui una volta per elemento".
Proprietà personalizzate
Poiché una funzione è un object, puoi aggiungervi le tue proprietà. Questo è diverso da una variabile locale: una proprietà vive sulla funzione e sopravvive tra una chiamata e l'altra, quindi è un modo ordinato per dare a una funzione il proprio stato persistente.
Un esempio classico è un contatore di chiamate:
Una proprietà di funzione non è la stessa cosa di una variabile all'interno della funzione. Una variabile locale si azzera ad ogni chiamata; una proprietà persiste, ed è anche leggibile e scrivibile dall'esterno, il che la rende utile per la configurazione (ad esempio per memorizzare i risultati nella cache direttamente sulla funzione).
Named Function Expression (NFE)
Una Named Function Expression è un'espressione di funzione che porta un nome dopo la parola chiave function:
let sayHi = function func(who) {
console.log("Hello, " + who);
};Questo sembra insolito — perché dare un nome a qualcosa già assegnato a sayHi? Il nome func qui è speciale in due modi:
- Consente alla funzione di riferirsi a se stessa in modo affidabile dall'interno del proprio corpo.
- È visibile solo all'interno della funzione — non puoi chiamare
func()dall'esterno.
Perché il nome interno è importante
Potresti pensare di poter usare semplicemente la variabile esterna sayHi per il riferimento a se stessa. Il problema è che la variabile esterna può cambiare. Con una NFE, il nome interno punta sempre alla funzione corrente, indipendentemente da cosa accade alla variabile:
Se la funzione avesse chiamato sayHi("Guest") invece di func("Guest"), la chiamata avrebbe generato un TypeError perché sayHi era stato impostato a null. Il nome interno è immune a questo problema.
NFE e ricorsione
Questo auto-riferimento è esattamente ciò di cui ha bisogno la ricorsione. Una NFE mantiene funzionante una chiamata ricorsiva anche se la funzione viene successivamente riassegnata o passata sotto un altro nome — vedi Ricorsione e Stack JavaScript per il quadro completo.
Nota che il trucco del nome interno si applica solo alle Expression di funzione. Una Function Declaration non può avere un nome interno separato, e non ha modo di nascondere un nome dall'ambito esterno, quindi non può mantenere un auto-riferimento privato allo stesso modo.
Quando usare queste funzionalità
- Usa
nameper log e output di debugging più chiari. - Usa
lengthquando scrivi librerie che si adattano all'arità di una callback. - Usa proprietà personalizzate per dare a una funzione uno stato persistente (contatori, cache, configurazione) senza una closure circostante o una variabile globale.
- Usa una Named Function Expression ogni volta che un'espressione di funzione deve chiamare se stessa — specialmente per la ricorsione o gli handler rimovibili — in modo che la chiamata sopravviva alla riassegnazione della variabile.
Riepilogo
Una funzione JavaScript è un object che puoi ispezionare ed estendere. La proprietà name fornisce il suo nome (spesso compilato in modo contestuale), length riporta il numero di parametri dichiarati e puoi aggiungere proprietà personalizzate per uno stato persistente. Una Named Function Expression aggiunge un nome solo interno che consente a una funzione di chiamare se stessa in modo affidabile, che è il modo più sicuro per scrivere espressioni di funzione auto-referenziali e ricorsive.