Introducción: ¿por qué la simple asignación es una trampa?
\nImagina que estás escribiendo una aplicación de notas. El usuario crea una tarjeta con un título y un texto, luego quiere hacer una copia para modificarla un poco. Escribes:
\nconst original = { title: 'Mi plan', text: 'Comprar leche' };\nconst copy = original;\ncopy.title = 'Nuevo plan';\nconsole.log(original.title); // 'Nuevo plan' — ¡uy!\n¿Te resulta familiar? Si es así, te has topado con la característica principal de los objetos en JavaScript: se pasan por referencia. La asignación copy = original no crea un nuevo objeto, solo copia la referencia a la misma ubicación de memoria. Cualquier cambio en copy se refleja en original.
En Stack Overflow, la pregunta "How do I correctly clone a JavaScript object?" ha acumulado miles de visitas y decenas de respuestas. Es uno de los problemas más comunes tanto para principiantes como para desarrolladores experimentados. En este artículo, analizaremos todas las formas de clonación de objetos en JavaScript, desde las simples hasta las avanzadas, y descubriremos qué enfoque es mejor en cada situación.
\n\nCopia superficial (Shallow copy): rápida y sencilla
\nLa copia superficial crea un nuevo objeto, pero para objetos anidados (arrays, otros objetos) solo copia las referencias. Es ideal para estructuras planas, pero peligrosa para las profundas.
\n\nMétodo 1: Operador spread (…)
\nLa forma más moderna y legible:
\nconst original = { name: 'Ana', age: 25 };\nconst clone = { ...original };\nclone.age = 30;\nconsole.log(original.age); // 25 — ¡todo bien!\nVentajas: escritura corta, funciona con arrays y objetos. Desventajas: no copia métodos (funciones) ni propiedades de tipo Symbol.
\n\nMétodo 2: Object.assign()
\nMétodo clásico para copiar un objeto sin referencias en el nivel superior:
\nconst source = { a: 1, b: { c: 2 } };\nconst target = Object.assign({}, source);\ntarget.a = 100; // source.a no cambiará\ntarget.b.c = 999; // source.b.c también cambiará — ¡shallow!\nEste método es especialmente útil cuando necesitas combinar varios objetos: Object.assign({}, obj1, obj2).
Método 3: Bucle for…in
\nUna forma antigua pero aún funcional. Útil para entender la mecánica:
\nfunction shallowClone(obj) {\n const clone = {};\n for (let key in obj) {\n if (obj.hasOwnProperty(key)) {\n clone[key] = obj[key];\n }\n }\n return clone;\n}\nHoy en día se usa raramente, pero demuestra perfectamente cómo funciona la clonación manual de objetos.
\n\nCopia profunda (Deep copy): cuando lo necesitas todo
\nSi tu objeto contiene objetos anidados, arrays o fechas, la shallow copy te fallará. Necesitas una clonación profunda js.
\n\nMétodo 4: JSON.parse + JSON.stringify
\nEl "parche" más popular:
\nconst original = { \n name: 'Pedro', \n address: { city: 'Moscú', street: 'Tverskaya' },\n date: new Date()\n};\nconst clone = JSON.parse(JSON.stringify(original));\nclone.address.city = 'SPb';\nconsole.log(original.address.city); // 'Moscú' — ¡bien!\nPero tiene matices: este método pierde funciones, undefined, Symbol, y Date se convierte en una cadena. Para datos simples está bien, para datos complejos no.
Método 5: structuredClone() — el nuevo estándar
\nDesde 2022, JavaScript tiene un método incorporado llamado structuredClone:
\nconst original = { \n scores: [10, 20, 30], \n meta: { level: 'easy' },\n date: new Date()\n};\nconst clone = structuredClone(original);\nclone.meta.level = 'hard';\nconsole.log(original.meta.level); // 'easy'\nVentajas: soporta Date, Map, Set, ArrayBuffer, referencias recursivas. Desventajas: no soporta funciones, elementos DOM, Error. Funciona