![]() |
La spread syntax (...) è diventata una delle funzionalità più comode e usate in JavaScript moderno per copiare oggetti e array. Tuttavia, c’è un aspetto importante da conoscere: la spread syntax crea una shallow copy (copia superficiale), non una deep copy (copia profonda). Questo comportamento può introdurre bug subdoli e difficili da tracciare.
Cos’è una Shallow Copy?
Una shallow copy copia solo il primo livello di un oggetto o array. Se ci sono oggetti annidati, questi non vengono clonati, ma copiati per riferimento.
Esempio: Shallow Copy con Oggetto
const originale = {
nome: 'Mario',
indirizzo: {
città: 'Roma',
cap: '00100'
}
};
const copia = { ...originale };
copia.nome = 'Luigi'; // OK, modifica indipendente
copia.indirizzo.città = 'Milano'; // ⚠️ Modifica anche l'oggetto originale!
console.log(originale.indirizzo.città); // "Milano" 😱
Esempio: Shallow Copy con Array
const arr = [[1, 2], [3, 4]];
const copiaArr = [...arr];
copiaArr[0][0] = 99;
console.log(arr[0][0]); // 99 😓
Perché succede?
Con la spread syntax:
- I valori primitivi (stringhe, numeri, booleani, ecc.) vengono copiati per valore.
- Gli oggetti (inclusi array) vengono copiati per referenza.
Questo significa che modifiche alle proprietà annidate della copia influenzano ancora l'originale.
Soluzioni: Come Evitare i Problemi della Shallow Copy
1. Deep Copy Manuale (Ricorsiva)
Per oggetti semplici, puoi scrivere una funzione ricorsiva:
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (Array.isArray(obj)) {
return obj.map(item => deepClone(item));
}
const result = {};
for (const key in obj) {
result[key] = deepClone(obj[key]);
}
return result;
}
const clone = deepClone(originale);
✔️ Pro: personalizzabile
❌ Contro: non gestisce tipi speciali come Date, Map, Set, funzioni, ecc.
2. Usare structuredClone (nativo) - consigliato ✅
A partire da ECMAScript 2021 (supportato nei browser moderni e in Node.js ≥ 17), è disponibile il metodo:
const copiaProfonda = structuredClone(originale);
✔️ Pro: sicuro, profondo, gestisce molti tipi di dati (Date, Map, ecc.)
❌ Contro: non supporta funzioni o oggetti con riferimenti circolari in ambienti obsoleti
3. JSON.parse(JSON.stringify(...))
Una tecnica popolare (ma con limiti):
const copia = JSON.parse(JSON.stringify(originale));
✔️ Pro: semplice, efficace per oggetti JSON
❌ Contro: perde metodi, undefined, Date, Map, funzioni, e causa errori su riferimenti circolari
4. Librerie Esterne (es. Lodash)
La funzione _.cloneDeep() di Lodash è una delle più robuste:
import cloneDeep from 'lodash/cloneDeep';
const copia = cloneDeep(originale);
✔️ Pro: gestisce quasi tutti i casi, inclusi riferimenti circolari
❌ Contro: dipendenza esterna, peso aggiuntivo
Quando va bene usare la Spread Syntax?
Usa ... solo quando:
- L’oggetto non ha proprietà annidate oppure
- Sei consapevole e intendi mantenere i riferimenti interni
Esempio sicuro:
const persona = { nome: 'Luca', età: 30 };
const copia = { ...persona };
copia.nome = 'Anna'; // ✅ Sicuro, effetto isolato
Conclusione
La spread syntax è potente e comoda, ma crea solo una shallow copy. Se il tuo oggetto ha strutture annidate, usala con attenzione o preferisci una delle tecniche di deep copy viste sopra.
In sintesi:
| Metodo | Tipo di copia | Pro | Contro |
|---|---|---|---|
... |
Shallow | Veloce, leggibile | Rischio aliasing |
deepClone() |
Deep (manuale) | Personalizzabile | Limitata |
structuredClone() |
Deep | Nativo, sicuro | Supporto da verificare |
JSON.stringify / parse() |
Deep | Facile | Perdita di tipo |
_.cloneDeep()(Lodash) |
Deep | Robusto | Dipendenza esterna |
Follow me #techelopment
Official site: www.techelopment.it
facebook: Techelopment
instagram: @techelopment
X: techelopment
Bluesky: @techelopment
telegram: @techelopment_channel
whatsapp: Techelopment
youtube: @techelopment
