DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 963,503 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for Maneras de clonar un objecto en javascript
Victor Hugo Aguilar
Victor Hugo Aguilar

Posted on • Updated on

Maneras de clonar un objecto en javascript

Ya que los objetos en javascript son valores por referencia, no pueden copiarse simplemente con el =. Aqui os dejo diferentes maneras de hacerlo.

let profesiones = { medico: 'πŸš‘', policia: 'πŸš“', bombero: 'πŸš’' }

// "Spread operator"
let clone_one = { ...profesiones }
console.log(clone_one) 
// clone_one { medico: 'πŸš‘', policia: 'πŸš“', bombero: 'πŸš’' }

// "Object.assign
let clone_two = Object.assign({}, profesiones)
console.log(clone_two) 
// clone_two { medico: 'πŸš‘', policia: 'πŸš“', bombero: 'πŸš’' }

// "JSON"
let clone_three = JSON.parse(JSON.stringify(profesiones))
console.log(clone_three) 
// clone_three { medico: 'πŸš‘', policia: 'πŸš“', bombero: 'πŸš’' }
Enter fullscreen mode Exit fullscreen mode

Los objetos son tipo referencia

Si utilizamos el operador de asignaciΓ³n pasa lo siguiente

const obj = { one: 1, two: 2 }

const obj2 = obj

console.log(
  obj, // {one: 1, two: 2}
  obj2, // {one: 1, two: 2}
);
Enter fullscreen mode Exit fullscreen mode

En principio es todo correcto, el problema viene cuando editamos por ejemplo el segundo objeto

const obj2.three = 3;

console.log(obj2);
// {one: 1, two: 2, three: 3} <- βœ…

console.log(obj);
// {one: 1, two: 2, three: 3} <- 😱
Enter fullscreen mode Exit fullscreen mode

Al ser objetos que van por tipo de referencia, cuando asignas '=' tambiΓ©n copias el puntero al espacio de memoria que ocupa. Los tipos de referencia no contienen valores, son un puntero al valor en la memoria.

Spread Operator

El uso del spread operator clonarΓ‘ el objecto, pero es una copia superficial del mismo.

let profesiones = { medico: 'πŸš‘', policia: 'πŸš“', bombero: 'πŸš’' }

let clone_spread = { ...profesiones }

console.log(clone_spread)
// clone_spread { medico: 'πŸš‘', policia: 'πŸš“', bombero: 'πŸš’' }
Enter fullscreen mode Exit fullscreen mode

Usando Object.assign

Esta opciΓ³n tambien crearΓ‘ una copia superficial del objeto.

let profesiones = { medico: 'πŸš‘', policia: 'πŸš“', bombero: 'πŸš’' }

let object_assign = Object.assign({}, profesiones)

console.log(object_assign)
// object_assign { medico: 'πŸš‘', policia: 'πŸš“', bombero: 'πŸš’' }
Enter fullscreen mode Exit fullscreen mode

Tener en cuenta el primer argumentoΒ {}, esto asegurarΓ‘ que no mute el objeto original

Usando JSON

EstΓ‘ manera si que darΓ‘ una copia profunda. Aunque es una manera sucia de hacerlo, pero rΓ‘pida.

let profesiones = { medico: 'πŸš‘', policia: 'πŸš“', bombero: 'πŸš’' }

let clone_json = JSON.parse(JSON.stringify( profesiones))

console.log(clone_json)
// clone_json { medico: 'πŸš‘', policia: 'πŸš“', bombero: 'πŸš’' }
Enter fullscreen mode Exit fullscreen mode

Utilizando librerias externa loadash

DeepClone funciona con todos los tipos, funciones y sΓ­mbolos, se copian por referencia

const lodashClonedeep = require('lodash.clonedeep')

let profesiones = { medico: 'πŸš‘', policia: 'πŸš“', bombero: 'πŸš’' }

let clone_lodash = lodashClonedeep(profesiones);

console.log(clone_lodash)
// clone_lodash { medico: 'πŸš‘', policia: 'πŸš“', bombero: 'πŸš’' }
Enter fullscreen mode Exit fullscreen mode

Ahora estΓ‘ libreria tiene una ventaja que tambiΓ©n clona todos los tipos, funciones y sΓ­mbolos se copian por referencia.

const lodashClonedeep = require('lodash.clonedeep')

const arrOfFunction = [
  () => 2,
  {
    test: () => 3,
  },
  Symbol('4'),
];

// deepClone copy by refence function and Symbol
console.log(lodashClonedeep(arrOfFunction))
// [ [Function (anonymous)], { test: [Function: test] }, Symbol(4) ]

// JSON replace function with null and function in object with undefined
console.log(JSON.parse(JSON.stringify(arrOfFunction)))
// [ null, {}, null ]

// function and symbol are copied by reference in deepClone
console.log(
  lodashClonedeep(arrOfFunction)[0] === lodashClonedeep(arrOfFunction)[0],
)
// true

console.log(
  lodashClonedeep(arrOfFunction)[2] === lodashClonedeep(arrOfFunction)[2],
)
// true
Enter fullscreen mode Exit fullscreen mode

El mΓ©todo JSON tiene problemas con las dependencias circulares. AdemΓ‘s, el orden de las propiedades en el objeto clonado puede ser diferente.

Β Cuando utilizar una clone superficial o profundo

Si utilizamos el spread operator, para copuar un objeto, solo se copia superficialmente, si la matriz estΓ‘ anidada o es multidimensional, no funcionarΓ‘ correctamente

const nestedObject = {
    name: 'batman',
    country: {
      city: 'gotam'
    }
}
Enter fullscreen mode Exit fullscreen mode

A. Copia Superficial

Clonamos el objeto y lo modificamos

const shallowClone = { ... nestedObject }

// modificamos los valores.
shallowClone.name = 'superman'
shallowClone.country.city = 'metropolis'

console.log(shallowClone);
// {name: 'superman', {city: 'metropolis'}}

console.log(nestedObject);
// {name: 'batman', {city: 'metropolis'}} <- 😱
Enter fullscreen mode Exit fullscreen mode

Una copia superficial significa que se copia el primer nivel, se hace referencia a los niveles mΓ‘s profundos.
En temas de perfomance decir que Object.assign es mucho mΓ‘s rΓ‘pido que JSON.

B. Copia Profunda

Tomemos el mismo ejemplo pero aplicando una copia profunda usando JSON

const deepClone = JSON.parse(JSON.stringify(nestedObject));

console.log(deepClone);
// {name: 'superman', {city: 'metropolis'}}

console.log(nestedObject);
// {name: 'batman', {city: 'gotam'}}

Enter fullscreen mode Exit fullscreen mode

Como puede ver, la copia profunda es una copia fiel de los objetos anidados. A menudo, la copia superficial es lo suficientemente buena, realmente no necesita una copia profunda.

Top comments (0)

Visualizing Promises and Async/Await 🀯

async await

☝️ Check out this all-time classic DEV post