Cómo clonar en profundidad un objeto JavaScript

JavaScript ofrece muchas formas de copiar un objeto, pero no todas proporcionan una copia profunda. Aprenda de la manera más eficiente y descubra también todas las opciones que tiene

Copiar objetos en JavaScript puede ser complicado. Algunas formas realizan una copia superficial, que es el comportamiento predeterminado en la mayoría de los casos.

Copia profunda vs copia superficial

Una copia superficial copia con éxitotipos primitivoscomo números y cadenas, pero cualquier referencia de objeto no se copiará de forma recursiva, sino que el nuevo objeto copiado hará referencia al mismo objeto.

Si un objeto hace referencia a otros objetos, al realizar unacopia superficialdel objeto, tucopia las referenciasa los objetos externos.

Al realizar unacopia profunda, aquelloslos objetos externos también se copian, por lo que el nuevo objeto clonado es completamente independiente del anterior.

Al buscar cómo clonar en profundidad un objeto en JavaScript en Internet, encontrará muchas respuestas, pero las respuestas sonno siempre correcto.

Opción más fácil: usa Lodash

Mi sugerencia para realizar una copia profunda es confiar en una biblioteca que esté bien probada, sea muy popular y se mantenga cuidadosamente: Lodash.

Lodash ofrece la muy convenientecloneydeepclonefunciones para realizar clonaciones superficiales y profundas.

Lodash tiene esta buena característica:puede importar funciones individuales por separadoen su proyecto para reducir mucho el tamaño de la dependencia.

En Node.js:

const clone = require('lodash.clone')
const clonedeep = require('lodash.clonedeep')

Aquí hay un ejemplo que muestra esas dos funciones en uso:

const clone = require('lodash.clone')
const clonedeep = require('lodash.clonedeep')

const externalObject = { color: ‘red’, }

const original = { a: new Date(), b: NaN, c: new Function(), d: undefined, e: function () {}, f: Number, g: false, h: Infinity, i: externalObject, }

const cloned = clone(original)

externalObject.color = ‘blue’

console.info(‘⬇️ shallow cloning 🌈’) console.info( ‘✏️ Notice the i.color property we changed on original is also changed in the shallow copy’ ) console.log(original) console.log(cloned)

const deepcloned = clonedeep(original)

externalObject.color = ‘yellow’ console.log(’’) console.info(‘⬇️ deep cloning 🌈’) console.info(‘✏️ Notice the i.color property does not propagate any more’) console.log(original) console.log(deepcloned)

En este ejemplo simple, primero creamos una copia superficial y editamos la propiedad i.color, que se propaga al objeto copiado.

En el clon profundo, esto no sucede.

Object.assign ()

Object.assign()realiza una copia superficial de un objeto, no un clon profundo.

const copied = Object.assign({}, original)

Al ser una copia superficial, los valores se clonan y las referencias de los objetos se copian (no los objetos en sí), por lo que si edita una propiedad de objeto en el objeto original, eso también se modifica en el objeto copiado, ya que el objeto interno al que se hace referencia es el mismo:

const original = {
  name: 'Fiesta',
  car: {
    color: 'blue',
  },
}
const copied = Object.assign({}, original)

original.name = ‘Focus’ original.car.color = ‘yellow’

copied.name //Fiesta copied.car.color //yellow

Uso del operador de propagación de objetos

losoperador de propagaciónes unES6 / ES2015característica que proporciona una forma muy conveniente de realizar un clon superficial, equivalente a lo queObject.assign()hace.

const copied = { ...original }

Soluciones incorrectas

En línea encontrará muchas sugerencias. Aquí hay algunos incorrectos:

Usando Object.create ()

Nota: no recomendado

const copied = Object.create(original)

Esto está mal, no está realizando ninguna copia.

En cambio, eloriginalobjeto se está utilizando como elprototipodecopied.

Aparentemente funciona, pero bajo el capó no lo es:

const original = {
  name: 'Fiesta',
}
const copied = Object.create(original)
copied.name //Fiesta

original.hasOwnProperty('name') //true
copied.hasOwnProperty('name') //false

Ver más enObject.create().

Serialización JSON

Nota: no recomendado

Algunos recomiendan transformarse enJSON:

const cloned = JSON.parse(JSON.stringify(original))

pero eso tiene consecuencias inesperadas.

Al hacer esto,perdercualquier propiedad de Javascript que no tenga un tipo equivalente en JSON, comoFunctionoInfinity. Cualquier propiedad asignada aundefinedserá ignorado porJSON.stringify, lo que hace que no aparezcan en el objeto clonado.

Además, algunos objetos se convierten en cadenas, como los objetos de fecha, por ejemplo (además, sin tener en cuenta la zona horaria y por defecto en UTC), Set, Map y muchos otros:

JSON.parse(
  JSON.stringify({
    a: new Date(),
    b: NaN,
    c: new Function(),
    d: undefined,
    e: function () {},
    f: Number,
    g: false,
    h: Infinity,
  })
)

Parsing as JSON

Esto solo funciona si no tiene ningún objeto y función internos, sino solo valores.


Más tutoriales de js: