Menu

Rest e spread in JavaScript: l'operatore ... spiegato

Come funziona l'operatore ... in JavaScript: raccogliere argomenti con i parametri rest, espandere array e oggetti con lo spread e quando usare l'uno o l'altro.

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

Stessa sintassi, due compiti

I tre punti ... compaiono spesso nel codice JavaScript moderno, e fanno due cose opposte a seconda di dove si trovano. Una volta capito lo schema, ogni uso di ... rientra in una di due categorie:

  • Rest: ...name dal lato di chi riceve raccoglie più valori in un unico array o oggetto.
  • Spread: ...value dal lato di chi dà espande un array o un oggetto nei suoi singoli pezzi.

Questo è l'intero modello mentale. Il resto della pagina sono solo esempi di ciascuno, e gli schemi che userai di continuo.

Parametri rest: raccogliere argomenti

Un parametro rest nella definizione di una funzione raccoglie un numero qualsiasi di argomenti in un vero array:

nums è un array normale. Puoi usare .map, .filter, controllarne la .length, passarlo a un'altra funzione: tutto ciò che fanno gli array.

I parametri rest si possono mescolare con i parametri normali, ma il parametro rest deve venire per ultimo:

label prende il primo argomento; tutto il resto finisce in items. Scrivere il parametro rest in una posizione diversa dall'ultima è un errore di sintassi.

Rest e il vecchio oggetto arguments

Il codice JavaScript più vecchio usa una variabile magica chiamata arguments dentro le funzioni normali. Sembra un array ma non lo è, il che significa che i metodi degli array non funzionano direttamente su di essa. I parametri rest la sostituiscono in modo pulito:

Le arrow function non hanno nemmeno un oggetto arguments, quindi i parametri rest sono l'unico modo per accettare un numero variabile di argomenti. Nel codice nuovo preferisci sempre ...args.

Spread nelle chiamate di funzione

Lo spread fa il contrario: prende un array e lo scompone in singoli argomenti nel punto della chiamata.

Math.max accetta singoli numeri, non un array. Prima dello spread avresti scritto Math.max.apply(null, nums). Ora basta un ... e hai finito.

Nota come lo stesso identico ... sia rest nella definizione della funzione e spread nella chiamata: è la posizione a dirti quale dei due è.

Spread nei letterali di array

Fare lo spread dentro un letterale di array copia o combina array:

[...a] ti dà un array nuovo con gli stessi elementi, utile quando vuoi ordinare o modificare senza toccare l'originale:

scores resta intatto perché .sort è stato eseguito sulla copia. Piccola abitudine, grande vantaggio quando scrivi codice che non deve avere effetti collaterali a sorpresa.

Spread nei letterali di oggetto

Lo spread funziona anche sugli oggetti semplici, unendo le loro proprietà in un oggetto nuovo:

Vincono le chiavi che vengono dopo. updates.age sovrascrive user.age, e city si aggiunge al resto. L'ordine degli spread determina il risultato: tienilo a mente quando sovrapponi valori predefiniti e personalizzazioni:

Prima i valori predefiniti, poi le scelte dell'utente. L'utente vince su fontSize ed eredita theme.

La trappola della copia superficiale

Lo spread copia un solo livello. Gli oggetti e gli array annidati restano condivisi tra l'originale e la copia:

Entrambi gli array mostrano il nuovo tag perché copy.tags e original.tags sono lo stesso array. Lo spread non ha clonato la lista annidata: ha solo copiato il riferimento.

Per una vera copia profonda di dati semplici, usa structuredClone:

Ora i due array sono indipendenti. structuredClone è integrato nei browser moderni e in Node, gestisce le strutture annidate ed è la scelta giusta ogni volta che una copia "superficiale" non basta.

Rest nella destrutturazione

Il rest funziona anche nella destrutturazione, dove raccoglie gli elementi o le proprietà rimanenti:

Estrarre qualche campo e tenere il resto in un unico oggetto è uno schema comune quando inoltri props, togli campi sensibili o costruisci versioni modificate dei dati:

password viene estratta (e ignorata); safe contiene tutto il resto. Nessuna modifica, nessuna copia manuale.

Riepilogo veloce

  • ...name in un elenco di parametri o in un pattern di destrutturazione è rest: raccoglie.
  • ...value in una chiamata di funzione, in un letterale di array o di oggetto è spread: espande.
  • Le copie con lo spread sono superficiali. Le strutture annidate restano condivise. Usa structuredClone per le copie profonde.
  • I parametri rest sono veri array: usali al posto di arguments.
  • Negli oggetti gli spread successivi sovrascrivono quelli precedenti, ed è così che costruisci valori predefiniti più personalizzazioni.

Prossimo passo: le closure

In JavaScript le funzioni non si limitano a ricevere input e restituire output: ricordano anche lo scope in cui sono state definite. Questa memoria si chiama closure, ed è il meccanismo dietro le callback, le factory e la maggior parte degli schemi che incontrerai nella prossima pagina.

Domande frequenti

Qual è la differenza tra rest e spread in JavaScript?

Usano la stessa sintassi ... ma fanno lavori opposti. Il rest raccoglie più valori in un unico array: compare negli elenchi di parametri delle funzioni e nella destrutturazione. Lo spread espande un iterabile o un oggetto nei suoi pezzi: compare nelle chiamate di funzione, nei letterali di array e nei letterali di oggetto. Se ... sta dal lato di chi riceve, è rest; se sta dal lato di chi dà, è spread.

Come funzionano i parametri rest in una funzione?

Un parametro rest come function sum(...nums) raccoglie ogni argomento passato alla funzione in un vero array chiamato nums. Deve essere l'ultimo parametro dell'elenco. A differenza del vecchio oggetto arguments, un parametro rest è un vero array, quindi .map, .filter e .reduce funzionano direttamente.

Lo spread operator fa una copia profonda?

No. Lo spread copia un solo livello: è una copia superficiale. { ...user } ti dà un nuovo oggetto con le stesse chiavi di primo livello, ma gli oggetti e gli array annidati restano riferimenti condivisi. Per una copia profonda usa structuredClone(value), oppure passa per JSON se si tratta di dati semplici.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA