Spread e Rest operator (...): stesso simbolo, lavori opposti
Copia, merge, parametri variadic — shallow copy oggetti, clone array
Tre puntini, ..., ma due significati opposti a seconda di dove li scrivi. Lo spread espande un array o un oggetto nei suoi elementi; il rest fa l'esatto contrario: raccoglie più elementi in un unico contenitore.
Pensa alla differenza tra svuotare uno scatolone rovesciandone il contenuto sul tavolo (spread: da uno, tanti pezzi separati) e riempire uno scatolone raccogliendo tutto ciò che trovi in giro (rest: da tanti pezzi, uno scatolone). Stesso gesto — «scatolone» — ma verso opposti.
1. Spread: da un contenitore, i suoi elementi separati
Lo spread prende un iterabile (array, stringa, o le proprietà di un oggetto) e lo espande dove ci si aspettano più valori: un elenco di argomenti, gli elementi di un nuovo array.
function somma(x, y, z) {
return x + y + z;
}
const numeri = [1, 2, 3];
somma(...numeri); // 6 -- come scrivere somma(1, 2, 3)
Math.max(...numeri); // 3 -- Math.max vuole valori separati, non un array
2. Copia array e oggetti: shallow, non deep
const originale = [1, 2, 3];
const copia = [...originale];
const obj1 = {
nome: "Ada",
x: 42
};
const clone = {
...obj1
};
Il punto tecnico da ricordare: lo spread crea una copia superficiale (shallow copy), senza il prototipo dell'oggetto originale, senza le proprietà non enumerabili. Se una proprietà contiene a sua volta un oggetto, quell'oggetto interno non viene duplicato: la copia e l'originale continuano a puntare allo stesso oggetto annidato.
const utente = {
nome: "Ada",
indirizzo: {
citta: "Roma"
}
};
const copiaUtente = {
...utente
};
copiaUtente.indirizzo.citta = "Milano";
console.log(utente.indirizzo.citta); // "Milano" -- cambiato anche l'originale!
Fonte: MDN Web Docs — «Spread syntax»: un singolo spread crea una copia superficiale dell'oggetto originale (senza proprietà non enumerabili e senza copiare il prototipo).
3. Merge: unire più oggetti, l'ordine decide chi vince
const base = {
tema: "chiaro",
lingua: "it"
};
const override = {
tema: "scuro"
};
const impostazioni = {
...base,
...override
};
// { tema: "scuro", lingua: "it" }
// override vince perché è scritto dopo
Quando due oggetti condividono la stessa proprietà, vince quella scritta per ultima nell'espressione. È lo stesso principio, applicato agli oggetti, dell'ultima dichiarazione che vince in un cascade CSS.
Una differenza sottile rispetto a Object.assign(), segnalata da MDN: lo spread non attiva gli eventuali setter definiti sull'oggetto di destinazione, mentre Object.assign() sì.
4. Rest: parametri «variadic», da tanti argomenti a un array
Nella lista dei parametri di una funzione, gli stessi tre puntini fanno il lavoro opposto: raccolgono un numero qualsiasi di argomenti in un vero array.
function sommaTutti(...numeri) {
return numeri.reduce((tot, n) => tot + n, 0);
}
sommaTutti(1, 2, 3, 4);
// 10 -- accetta quanti argomenti vuoi
Il rest parameter, per sintassi obbligatoria, deve essere l'ultimo della lista dei parametri, se ne scriviamo un altro dopo è un errore.
// Errore: il rest deve essere l'ultimo parametro
// function f(a, ...resto, b) { }
// Corretto
function f(a, ...resto) {
}
In sintesi
| Cosa fa | Esempio | |
|---|---|---|
| Spread in chiamata | Espande un array come argomenti separati | somma(...numeri) |
| Spread in array | Copia o unisce array | [...arr1, ...arr2] |
| Spread in oggetto | Copia o unisce oggetti (shallow) | { ...obj1, ...obj2 } |
| Rest in parametri | Raccoglie argomenti in un array | function f(...args) {} |
Stesso simbolo, stessa parola nel nome, ma dove lo scrivi decide se stai aprendo un contenitore o chiudendone uno. Ricordarsi che la copia è sempre superficiale evita uno dei bug più comuni e silenziosi in JavaScript: modificare per sbaglio l'originale credendo di lavorare solo sulla copia.
Commenti (0)
Registrati per commentare, fare domande e proporre l'argomento della prossima pillola (oppure accedi se hai già un account).
Nessun commento. Sii il primo a scrivere qualcosa.