← JavaScript

Arrays y objetos

¿Cuál es la diferencia entre una copia superficial y una copia profunda?

Ver respuesta — intenta responderla en voz alta primero

Una copia superficial solo copia el nivel superior; los objetos o arreglos anidados siguen compartiendo la misma referencia. Una copia profunda copia todo, incluidos los niveles anidados, creando objetos totalmente independientes.

Cuando copias un objeto con spread ({...obj}) o Object.assign, obtienes una copia superficial: las propiedades del nivel superior son nuevas, pero si hay otro objeto o arreglo dentro, ese se mantiene igual (comparten una referencia). Modificar el objeto anidado en la copia también afecta al original.

Una copia profunda clona todo, hasta el fondo, así que el original y la copia quedan completamente separados.

Formas de hacer una copia profunda:

  • structuredClone(obj) — el enfoque moderno y recomendado.
  • JSON.parse(JSON.stringify(obj)) — funciona, pero pierde funciones y undefined, convierte las fechas en strings, etc.
// Copia superficial: el nivel anidado se comparte
const original = {
  nombre: "Mike",
  direccion: { ciudad: "Ciudad de México" },
};

const superficial = { ...original };
superficial.nombre = "Alguien";              // solo afecta a la copia
superficial.direccion.ciudad = "Puebla";     // afecta a AMBOS

console.log(original.nombre);                 // "Mike" (independiente)
console.log(original.direccion.ciudad);       // "Puebla" (la referencia se compartió)

// Copia profunda con structuredClone
const original2 = { direccion: { ciudad: "Ciudad de México" } };
const profunda = structuredClone(original2);
profunda.direccion.ciudad = "Monterrey";

console.log(original2.direccion.ciudad); // "Ciudad de México" (intacto)
console.log(profunda.direccion.ciudad);  // "Monterrey"

Pensar que {...obj} o Object.assign hacen una copia completa. Solo copian el nivel superior. Si el objeto tiene datos anidados, modificarlos en la "copia" también cambia el original, lo que provoca bugs muy difíciles de rastrear.

"Una copia superficial, como la que hago con el operador spread, solo copia el nivel superior; los objetos o arreglos anidados siguen apuntando a la misma referencia, así que modificarlos afecta al original. Una copia profunda clona todo hasta el fondo y deja los objetos completamente independientes. Para una copia profunda uso structuredClone, que es el enfoque moderno; antes se usaba JSON.parse(JSON.stringify()), pero eso pierde funciones y convierte las fechas en strings."

Reto rápido

¿Qué imprime esto?

const a = { lista: [1, 2] };
const b = { ...a };
b.lista.push(3);
console.log(a.lista);
Ver respuesta

Imprime [1, 2, 3]. El spread hace una copia superficial, así que a.lista y b.lista son el mismo arreglo. Llamar a push sobre b.lista también cambia el de a.