➿ Attenzione alla Shallow Copy con la Spread Syntax in JavaScript: Esempi e Soluzioni

  


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.

🔗 Ti piace Techelopment? Dai un'occhiata al sito per tutti i dettagli!

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