Clonación profunda de un objeto en JavaScript
- Copia superficial frente a copia profunda
- Métodos de copia superficial en JavaScript
- Métodos de copia profunda en JavaScript
JavaScript es un lenguaje de objetos. Casi todo es un objeto en JavaScript. Booleanos, números, cadenas, fechas, matemáticas, expresiones regulares, matrices, funciones y los objetos en sí, todos son objetos. Son una colección de pares clave-valor que consta de varios atributos y métodos. Se almacenan directamente en la memoria y solo se pueden copiar por referencia. Una variable no almacena el objeto sino solo una referencia a ese objeto en la memoria. Entonces, cuando intentamos copiar una variable de objeto, terminamos creando una referencia adicional al mismo objeto. Este método se llama copia superficial. No es ideal ya que no queremos que el cambio en el objeto original afecte a su clon. Esto crea la necesidad de un método para clonar en profundidad el objeto. Este tutorial enseña cómo clonar en profundidad un objeto en JavaScript.
Copia superficial frente a copia profunda
Una copia superficial es una copia bit a bit del objeto. El nuevo objeto creado copia correctamente las primitivas como números, booleanos y cadenas, pero no copia ninguna referencia a los objetos. Solo las direcciones de referencia dan como resultado un puntero que apunta al mismo objeto. Cualquier cambio realizado en el objeto original se refleja en la copia superficial.
Por otro lado, una copia profunda no copia solo la dirección/referencia al objeto original, sino todo el objeto. El nuevo objeto creado no depende del objeto copiado. JavaScript nos proporciona varios métodos integrados para copiar un objeto, pero la copia superficial es el comportamiento predeterminado en la mayoría de ellos.
Métodos de copia superficial en JavaScript
Cubriremos brevemente los métodos de copia superficial para que conozca algunas de las formas incorrectas de copia profunda.
Use la sintaxis de propagación para clonar superficialmente un objeto en JavaScript
Podemos clonar un objeto creando un nuevo objeto y luego usando la sintaxis de propagación para enumerar el contenido de un objeto dentro de él como propio. Parece la forma correcta, pero crea una copia superficial de los datos.
const obj = {
a: 1,
b: {c: 2}
}
const clone = {...obj}; // creates a shallow copy
obj.b.c = 5;
console.log(clone.b.c); // outputs 5
En el código anterior, usamos la sintaxis spread
para crear una copia superficial del objeto. Luego modificamos una de las propiedades del objeto referenciado en el objeto original y mostramos que la propiedad se modifica en el objeto clonado.
Utilice Object.assign()
para clonar superficialmente un objeto en JavaScript
El método object.assign()
asigna una copia superficial del objeto a una nueva variable de objeto. Se necesitan dos argumentos: destino y origen. El target
suele ser un par de paréntesis vacíos que se utilizan para representar el objeto vacío en el que copiar; es un argumento opcional pero pasarlo asegura que no terminemos cambiando el objeto original. El segundo argumento es el objeto a copiar.
const obj = {
a: 1,
b: {c: 2}
}
const clone = Object.assign({}, obj); // creates a shallow copy
obj.b.c = 5;
console.log(clone.b.c); // outputs 5
En el código anterior, usamos Object.assign()
para crear una copia superficial del objeto. Luego modificamos una de las propiedades del objeto referenciado en el objeto original y mostramos que la propiedad se modifica en el objeto clonado.
Métodos de copia profunda en JavaScript
Utilice JSON.parse()
y JSON.stringify()
para clonar en profundidad un objeto en JavaScript
JSON.stringify()
se usa para convertir un objeto JavaScript en una cadena JSON y JSON.parse()
se usa para convertir una cadena JSON en un objeto JavaScript. Podemos envolver JSON.parse()
alrededor de JSON.stringify()
para convertir primero el objeto JavaScript en JSON String y luego analizarlo para obtener una copia del objeto.
var user = {name: 'Harshit', age: 21, Profession: 'Software Engineer'};
let fakeDeepCopy = JSON.parse(JSON.stringify(user));
Este método crea una copia profunda, pero solo para objetos sin funciones. Tiene problemas con las dependencias circulares como otros objetos referenciados. El orden de las propiedades del objeto copiado también puede diferir del objeto original. Entonces, este método es un buen truco si tenemos un objeto simple con pocos tipos de datos primitivos, pero no se recomienda para el mundo real.
Utilice la clonación profunda nativa para clonar en profundidad un objeto en JavaScript
Podemos usar el algoritmo de serialización del módulo Node.js v8
para clonar en profundidad un objeto. Aunque está limitado a ciertos tipos de datos integrados, conserva las referencias dentro de los datos clonados. Nos permite copiar varias estructuras cíclicas y recursivas que no eran compatibles con el método JSON.
const v8 = require('v8');
const structuredClone = obj => {
return v8.deserialize(v8.serialize(obj));
};
Deserializamos y luego serializamos el objeto al igual que los métodos JSON stringify y parse. Pero conserva las dependencias circulares y es un poco mejor.
Utilice la biblioteca Lodash para clonar en profundidad un objeto en JavaScript
La biblioteca Lodash tiene funciones para copia superficial y profunda, a saber, clone
y clonedeep
. Es una gran biblioteca que nos permite importar solo las funciones que necesitamos y no la biblioteca completa. El método clonedeep
funciona copiando recursivamente el valor y luego conservando todas las herencias del objeto, creando una copia fiel del objeto.
const lodashClonedeep = require('lodash.clonedeep');
let obj = {a: 1, b: {c: 2}} let deepClone = lodashClonedeep(obj);
Aquí cargamos la función clonedeep
de lodash y la usamos para clonar en profundidad el objeto. Es una biblioteca bien probada y mantenida, pero solo se puede usar con Node.js y no con Vanilla JavaScript.
Utilice el método jQuery extend()
para clonar en profundidad un objeto en JavaScript
Podemos usar .extend()
de jQuery para realizar copias superficiales y profundas de un objeto. Es el método de clonación profunda más confiable sin pérdida de datos ni corrupción de datos. Su función principal es fusionar dos o más objetos. Pero también se puede usar para clonar un objeto. Toma los siguientes argumentos: [deep]
, target
, object1 ..... objectN
.
[deep]
: Es un argumento opcional. Su único valor permitido es verdadero. Si se pasa en la función, la función crea una copia profunda del objeto. De lo contrario, forma una copia superficial.target
: el objeto que se va a ampliar. Recibirá todos los objetos fusionados.object1, ..., objectN
: estos son los objetos que se fusionarán/clonarán en un nuevo objeto.
let obj = {a: 1, b: {c: 2}} let shallowClone =
$.extend({}, obj); // creates a shallow copy
let deepClone = $.extend(true, {}, obj); // creates a deep copy
Una solución más obvia puede ser simplemente iterar a través de cada propiedad del objeto fuente y replicarlas en un nuevo objeto. Todos los métodos discutidos anteriormente son compatibles con los principales navegadores.
Harshit Jindal has done his Bachelors in Computer Science Engineering(2021) from DTU. He has always been a problem solver and now turned that into his profession. Currently working at M365 Cloud Security team(Torus) on Cloud Security Services and Datacenter Buildout Automation.
LinkedIn