Lo spread espande un oggetto dentro un altro
La sintassi spread per gli oggetti, cioè tre puntini davanti a un oggetto, copia le proprietà proprie ed enumerabili di quell'oggetto nell'oggetto letterale che lo contiene. È la strada più breve per clonare, unire e produrre copie modificate senza toccare l'originale.
copy ha le stesse chiavi e gli stessi valori di user, ma è un oggetto diverso. Modificare l'uno non tocca l'altro, almeno al primo livello. Torneremo su questa precisazione tra poco.
Il modello mentale: { ...obj } significa "versa le proprietà di obj in questo nuovo oggetto letterale". Tutto quello che scrivi accanto allo spread entra a far parte del risultato.
Clonare e sovrascrivere in un solo passaggio
Lo schema più comune è espandere un oggetto e poi aggiungere o sovrascrivere qualche proprietà. Vince l'ultima chiave, quindi prima metti lo spread e poi le sovrascritture:
user resta intatto. updated è un oggetto nuovo con role sostituito. Questo schema di aggiornamento immutabile compare ovunque nel JavaScript moderno: nei setter di stato di React, nei reducer di Redux, in qualsiasi codice che preferisce non modificare i dati sul posto.
Inverti l'ordine e ottieni il comportamento opposto:
Qui role: "guest" viene prima, quindi user.role lo sovrascrive. È comodo quando vuoi dei valori predefiniti che l'oggetto espanso può sovrascrivere.
Unire oggetti in JavaScript
Per unire due (o più) oggetti, espandili in un nuovo oggetto letterale. In caso di chiavi in conflitto, gli oggetti successivi sovrascrivono quelli precedenti:
theme e fontSize arrivano da userPrefs; debug resta quello di defaults. Tre oggetti? Quattro? Stessa regola: leggi da sinistra a destra, vince l'ultima scrittura.
È il sostituto moderno di Object.assign({}, defaults, userPrefs). Fanno la stessa cosa, ma la versione con spread si legge meglio e non ti spinge nel classico bug di scrivere Object.assign(defaults, userPrefs), che modifica defaults.
Lo spread fa una copia superficiale
Ecco il punto che frega molte persone. Lo spread copia le proprietà di primo livello di un oggetto. Se il valore di una proprietà è a sua volta un oggetto o un array, viene copiato il riferimento, non il contenuto.
Cambiare copy.address.city ha cambiato anche user.address.city, perché i due oggetti condividono lo stesso oggetto address. Lo spread ci ha dato solo un nuovo involucro esterno.
Quando devi modificare qualcosa di annidato, espandi ogni livello che vuoi cambiare:
Per una vera copia profonda di dati qualsiasi, usa structuredClone(obj). Gestisce oggetti annidati, array, date, map e set, ed è integrato in ogni runtime moderno.
Spread vs. rest in JavaScript
Condividono gli stessi tre puntini ma fanno cose opposte. Lo spread espande; il rest raccoglie.
La regola pratica: se i ... stanno a sinistra di un = (destrutturazione), è rest. Se stanno dentro un oggetto o un array letterale a destra, è spread.
Rimuovere una proprietà in modo immutabile
Combinando la destrutturazione con rest e lo spread ottieni un modo pulito per produrre una copia di un oggetto senza una chiave: niente delete, niente modifiche:
tempToken finisce in una variabile tutta sua (che ignori) e tutto il resto arriva in safe. L'oggetto user originale resta intatto.
Cosa non copia lo spread
Qualche sottigliezza da conoscere:
- Le proprietà non enumerabili non vengono copiate. La maggior parte delle proprietà che crei è enumerabile di default, ma quelle definite con
Object.definePropertye alcune proprietà native non lo sono. - Il prototipo non viene copiato.
{ ...instance }ti dà un oggetto semplice, non un'istanza della classe originale. I metodi definiti sul prototipo della classe non ci saranno nella copia. - I getter vengono eseguiti. Espandere un oggetto con un getter chiama il getter una volta e salva il valore restituito come proprietà normale nel nuovo oggetto.
copy ha x e y, ma è un oggetto semplice: distance vive su Point.prototype, che lo spread non ha toccato. Se devi clonare un'istanza di una classe, di solito è la classe stessa a dover fornire un metodo clone.
Prossimo passo: i metodi degli array
Lo spread è un pezzo del kit per i dati immutabili. L'altro grande pezzo sono i metodi degli array, cioè map, filter, reduce e compagnia, che producono array nuovi invece di modificare gli originali. È l'argomento della prossima pagina.
Domande frequenti
Cosa fa ...obj in JavaScript?
Dentro un oggetto letterale, ...obj copia nel nuovo oggetto tutte le proprietà proprie ed enumerabili di quell'oggetto. { ...user } produce un oggetto nuovo con le stesse chiavi e gli stessi valori di user. È il modo standard per clonare o unire oggetti senza modificare gli originali.
Come unisco due oggetti in JavaScript?
Espandi entrambi in un nuovo oggetto letterale: const merged = { ...a, ...b }. Le proprietà di b sovrascrivono quelle di a con la stessa chiave, perché vince l'ultima. È equivalente a Object.assign({}, a, b), ma si legge meglio.
Lo spread degli oggetti fa una copia profonda?
No. Lo spread fa una copia superficiale (shallow copy): copia le proprietà di primo livello, ma oggetti e array annidati restano condivisi per riferimento. Se modifichi copy.address.city, cambia anche original.address.city. Per una vera copia profonda, usa structuredClone(obj).
Qual è la differenza tra spread e rest?
Si scrivono allo stesso modo (...) ma fanno l'esatto contrario. Lo spread espande un oggetto o un array in singole proprietà o elementi: { ...user }. Il rest raccoglie ciò che avanza in una sola variabile: const { name, ...others } = user. È il contesto a dirti quale dei due stai guardando.