Menu

for...of e for...in in JavaScript: array e oggetti

Le vere differenze tra for...of e for...in in JavaScript: valori contro chiavi, array contro oggetti, e quando usare l'uno o l'altro.

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

Due cicli, due compiti diversi

JavaScript ha due forme di ciclo che sembrano quasi identiche ma fanno cose molto diverse. for...of scorre i valori di un iterabile. for...in scorre le chiavi di un oggetto. Una lettera di differenza, un comportamento completamente diverso.

Ecco tutta la storia in un solo esempio:

Il primo ciclo stampa apple, banana, cherry: i valori. Il secondo stampa 0, 1, 2: le chiavi, e per di più come stringhe. Se sbagli ciclo, passerai dieci minuti a chiederti perché il tuo array è pieno di numeri.

for...of: valori da qualsiasi iterabile

for...of è il ciclo che userai più spesso. Funziona con tutto ciò che JavaScript considera iterabile: array, stringhe, Map, Set, NodeList, generatori e altro ancora.

Niente acrobazie con gli indici, niente scores[i]. Chiedi ogni valore e ricevi ogni valore. Anche le stringhe sono iterabili, quindi for...of le scorre carattere per carattere:

Funziona correttamente anche con la maggior parte dei code point Unicode, un vantaggio piccolo ma reale rispetto all'accesso ai caratteri di una stringa tramite indice numerico.

Ottenere l'indice con for...of

L'unica cosa che for...of non ti dà direttamente è la posizione. Quando ti serve, abbina il ciclo a entries():

names.entries() produce coppie [indice, valore], e il destructuring a sinistra le separa in due variabili. Di solito è più pulito che tornare al classico for (let i = 0; ...) solo perché ti serve i.

for...in: le chiavi di un oggetto

for...in è pensato per gli oggetti semplici. Itera sulle chiavi enumerabili di tipo stringa:

Nota che ottieni la chiave, non il valore. Per leggere il valore, accedi di nuovo all'oggetto con user[key]. Ogni chiave è una stringa, anche quando sembra un numero.

for...in risale anche la catena dei prototipi, quindi può far emergere proprietà ereditate. Con i tuoi oggetti letterali raramente è un problema, ma quando iteri istanze di una classe o oggetti che arrivano da una libreria conviene essere prudenti:

Object.hasOwn(user, key) salta tutto ciò che è ereditato. Nel codice moderno, la maggior parte delle persone evita del tutto for...in e usa Object.keys, Object.values o Object.entries, che è proprio l'argomento della prossima sezione.

Il modo moderno di scorrere un oggetto

Invece di for...in, combina for...of con uno degli helper Object.*. Scegli quello dei tre che corrisponde a ciò che ti serve:

Object.entries è particolarmente comodo: destrutturare la coppia [key, value] si legge quasi come una frase. E siccome questi metodi restituiscono solo le proprietà proprie ed enumerabili dell'oggetto, non devi preoccuparti della spazzatura ereditata.

Non usare for...in sugli array

Tecnicamente è consentito, ma fa inciampare molte persone:

Ottieni 0, 1, 2 e tag. Qualsiasi proprietà che qualcuno abbia aggiunto all'array, o a Array.prototype tramite un polyfill, compare anche lei. Le chiavi sono stringhe, quindi key + 1 concatena invece di sommare. E l'ordine di iterazione non è garantito uguale a quello dell'array in tutti i casi limite.

Regola pratica:

  • Valori dell'array? for...of arr.
  • Indice e valore dell'array? for...of arr.entries().
  • Solo l'indice, per contare? Il classico for (let i = 0; i < arr.length; i++).
  • Chiavi o voci di un oggetto? Object.keys(obj) / Object.entries(obj) con for...of.

In sostanza: for...in è uno strumento di nicchia. for...of più gli helper di Object copre tutto ciò che ti serve.

break e continue funzionano in entrambi

Entrambi i cicli supportano i soliti strumenti di uscita anticipata:

continue passa all'iterazione successiva; break esce del tutto dal ciclo. È il motivo principale per preferire for...of a .forEach(): le callback di forEach non possono uscire dal ciclo con break, mentre for...of sì.

Riepilogo a confronto

Quattro cicli, quattro compiti, un solo modello mentale: se vuoi i valori di qualcosa di iterabile, usa for...of. Se vuoi lavorare con le proprietà di un oggetto, passa da Object.keys / Object.values / Object.entries, sempre con for...of. Lascia for...in per il raro caso in cui vuoi davvero ogni chiave stringa enumerabile di un oggetto, ereditata o no.

Prossimo passo: valori truthy e falsy

Ogni ciclo e ogni if in JavaScript finisce per porsi la stessa domanda: questo valore è considerato vero? La risposta non è sempre ovvia: stringhe vuote, zero, null e undefined si comportano in modo diverso da come potresti aspettarti. I valori truthy e falsy sono il prossimo argomento.

Domande frequenti

Qual è la differenza tra for...of e for...in in JavaScript?

for...of scorre i valori di un iterabile come un array, una stringa, una Map o un Set. for...in invece scorre le chiavi (i nomi delle proprietà) di un oggetto. Per un array come ['a', 'b'], for...of ti restituisce 'a' e 'b'; for...in ti dà '0' e '1' come stringhe.

Posso usare for...of su un oggetto?

Non direttamente: gli oggetti semplici non sono iterabili. Usa Object.keys(obj), Object.values(obj) o Object.entries(obj) per ottenere un array che puoi scorrere con for...of. Lo schema più comune è for (const [key, value] of Object.entries(obj)).

Perché non dovrei usare for...in sugli array?

Tecnicamente funziona, ma for...in visita ogni proprietà enumerabile, comprese quelle ereditate e qualsiasi aggiunta fatta da qualcuno a Array.prototype. Restituisce anche le chiavi come stringhe, e l'ordine non è garantito al 100% per le chiavi numeriche in ogni caso. Usa for...of per i valori, oppure un ciclo for classico quando ti serve l'indice.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA