La clonación superficial copia solo las propiedades de un objeto, pero no las referencias a otros objetos dentro de él. Esto significa que si el objeto contiene propiedades que son otros objetos, estas referencias seguirán apuntando a los mismos objetos después de la clonación.
El spread operator (...
) es una forma sencilla y moderna de realizar una clonación superficial de un objeto.
const original = { a: 1, b: 2, c: { d: 3 } };
const copia = { ...original };
console.log(copia); // { a: 1, b: 2, c: { d: 3 } }
console.log(copia.c === original.c); // true
Object.assign()
Otra manera de realizar una clonación superficial es mediante el método Object.assign()
.
const original = { a: 1, b: 2, c: { d: 3 } };
const copia = Object.assign({}, original);
console.log(copia); // { a: 1, b: 2, c: { d: 3 } }
console.log(copia.c === original.c); // true
La clonación profunda implica la copia de todas las propiedades, incluidas las referencias a otros objetos, de modo que las copias no compartan referencias con el objeto original.
Una técnica común para la clonación profunda es convertir el objeto a una cadena JSON y luego volver a convertirlo a un objeto.
const original = { a: 1, b: 2, c: { d: 3 } };
const copia = JSON.parse(JSON.stringify(original));
console.log(copia); // { a: 1, b: 2, c: { d: 3 } }
console.log(copia.c === original.c); // false
Esta técnica tiene limitaciones, ya que no puede clonar funciones, fechas, undefined
, y otros tipos de datos especiales.
Para una clonación profunda más completa, se puede implementar una función recursiva personalizada.
function clonarProfundo(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (Array.isArray(obj)) {
const copia = [];
for (let i = 0; i < obj.length; i++) {
copia[i] = clonarProfundo(obj[i]);
}
return copia;
}
const copia = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
copia[key] = clonarProfundo(obj[key]);
}
}
return copia;
}
const original = { a: 1, b: 2, c: { d: 3 } };
const copia = clonarProfundo(original);
console.log(copia); // { a: 1, b: 2, c: { d: 3 } }
console.log(copia.c === original.c); // false
Esta función recursiva maneja arrays y objetos anidados correctamente.
El spread operator también puede utilizarse para clonar superficialmente arrays.
const original = [1, 2, { a: 3 }];
const copia = [...original];
console.log(copia); // [1, 2, { a: 3 }]
console.log(copia[2] === original[2]); // true
Array.prototype.slice()
El método slice()
crea una nueva copia superficial del array.
const original = [1, 2, { a: 3 }];
const copia = original.slice();
console.log(copia); // [1, 2, { a: 3 }]
console.log(copia[2] === original[2]); // true
La técnica de JSON puede aplicarse a arrays para lograr una clonación profunda.
const original = [1, 2, { a: 3 }];
const copia = JSON.parse(JSON.stringify(original));
console.log(copia); // [1, 2, { a: 3 }]
console.log(copia[2] === original[2]); // false
Podemos adaptar nuestra función recursiva para manejar arrays y objetos.
function clonarProfundo(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (Array.isArray(obj)) {
const copia = [];
for (let i = 0; i < obj.length; i++) {
copia[i] = clonarProfundo(obj[i]);
}
return copia;
}
const copia = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
copia[key] = clonarProfundo(obj[key]);
}
}
return copia;
}
const original = [1, 2, { a: 3 }];
const copia = clonarProfundo(original);
console.log(copia); // [1, 2, { a: 3 }]
console.log(copia[2] === original[2]); // false
La elección entre clonación superficial y profunda depende del contexto y de la naturaleza de los datos con los que se trabaja. La clonación superficial es rápida y suficiente para estructuras de datos simples, mientras que la clonación profunda es más adecuada para estructuras de datos complejas y anidadas.
Es crucial entender las limitaciones y el comportamiento de cada método para evitar errores y efectos secundarios no deseados en la manipulación de datos en aplicaciones JavaScript. Con las herramientas y técnicas adecuadas, se puede gestionar eficazmente la clonación de objetos y arrays para mantener la integridad de los datos y mejorar la robustez del código.
Jorge García
Fullstack developer