馃枛 Inicio

SERVICIOS

Salir

noched铆a

C贸mo copiar un object en JavaScript? no es tan sencillo como parece

600 palabras
2 minutos
June 10, 2019
blogjavascript

Te explico c贸mo copiar objetos en JavaScript y por qu茅 no es tan sencillo como parece

  1. Pr贸logo
  2. Copia simple
  3. Copia shallow (superficial)
  4. Copia deep
  5. Resumen

Pr贸logo

Copiar un object y no simplemente modificarlo no es tan sencillo como puede parecer, puesto que si bien podemos copiar la referencia a la estructura (el objeto), esa estructura seguir谩 siendo la misma con lo que si la modificamos, todas las referencias se ver谩n modificadas por igual

El s铆mil de una referencia ser铆a copiar la direcci贸n a un edificio en lugar de copiar todo el edificio, por lo que al guardar una copia de la direcci贸n, si luego modificas el edificio todas las referencias a ese edificio apuntar谩n al edificio modificado

Pero hay veces que necesitamos una copia real, lo que se entiende como deep copy (copia profunda), y es lo que voy a explicar en esta entrada

Copia simple

Con el siguiente c贸digo podr铆a pensar que ya lo tengo todo hecho, pero como ves, al cambiar el objeto original myObj tambi茅n se cambia el objeto copia myObjCopy

js
let myObj = {site: 'https://www.kuworking.com/'}
console.log(myObj.site) // https://www.kuworking.com/
let myObjCopy = myObj
console.log(myObjCopy.site) // https://www.kuworking.com/
myObj.site = 'https://www.kuworking2.com'
console.log(myObj.site) // https://www.kuworking2.com
console.log(myObjCopy.site) // https://www.kuworking2.com

Esto ocurre porque si bien myObjCopy s铆 que almacena una referencia nueva al objeto, el objecto es el mismo: tanto myObj como myObjCopy apuntan al mismo object

Por lo tanto lo que tengo no son dos objetos sino dos referencias del objeto

Siguiendo el s铆mil anterior, he hecho una copia de la direcci贸n, no del edificio

Copia shallow (superficial)

Por copia superficial se entiende una copia del objeto a un s贸lo nivel, esto es, si tenemos un objeto como el siguiente:

js
let myObj = {
site: 'https://www.kuworking.com/',
data: {
type: 'blog',
location: 'barcelona',
}
}

Una copia shallow nos dar谩 un object que ser谩 una copia real en myObj y en myObj.site, pero m谩s all谩 del primer nivel s贸lo ser谩n referencias y por lo tanto myObj.data.type y myObj.data.location se referir谩n al objeto original

En otras palabras, hago una copia de la fachada del edificio, pero lo que va m谩s all谩 sigue siendo una direcci贸n

Esta copia superficial o shallow copy se hace con Object.assign()

js
let myObj = {
site: 'https://www.kuworking.com/',
data: {
type: 'blog',
location: 'barcelona',
}
}
let myObjCopy = Object.assign({}, myObj)
myObjCopy.site = 'https://www.kuworking2.com'
myObjCopy.data.type = 'laptops'
console.log(myObj)
console.log(myObjCopy)
/*
{
"site": "https://www.kuworking.com/",
"data": {
"type": "laptops",
"location": "barcelona"
}
}
{
"site": "https://www.kuworking2.com",
"data": {
"type": "laptops",
"location": "barcelona"
}
}
*/

Como ves, el cambio de myObjCopy.data.type ha afectado a los dos objetos por igual, mientras que el cambio de myObjCopy.site s铆 que s贸lo ha afectado a la copia shallow del objeto myObjCopy

Copia deep

Para copiar todo el objeto, esto quiere decir todos los elementos contenidos en el objeto, lo idea ser铆a tener una funci贸n dedicada para ello

Pero no la tenemos, el Object.assign deber铆a ocupar ese sitio pero ya hemos visto que s贸lo nos da una copia de un nivel

La soluci贸n caer铆a casi dentro de la categor铆a de hack o dirty workaround, pero lo cierto es que funciona y es ampliamente utilizado

Se trata de convertir el objeto a texto, y luego volver a convertir el texto en objeto, y de esta forma se pierden las referencias originales y se hace todo de nuevo, lo que equivale a hacer un objet totalmente nuevo, o lo que es lo mismo, un deep clone

Totalmente? No, los elementos que no son variables sino que son m茅todos, se $1, mientras que con Object.assign() s铆 se copian los m茅todos

Se hace con JSON.stringify y JSON.parse

js
let myObj = {
site: 'https://www.kuworking.com/',
data: {
type: 'blog',
location: 'barcelona',
}
}
let myObjCopy = JSON.parse(JSON.stringify(myObj))
myObjCopy.site = 'https://www.kuworking2.com'
myObjCopy.data.type = 'laptops'
console.log(myObj)
console.log(myObjCopy)
/*
{
"site": "https://www.kuworking.com/",
"data": {
"type": "blog",
"location": "barcelona"
}
}
{
"site": "https://www.kuworking2.com",
"data": {
"type": "laptops",
"location": "barcelona"
}
}
*/

Y efectivamente, ahora he podido hacer una deep copy del object y cambiar las propiedades de cualquiera sin que afecte al otro

Resumen

Copiar objetos deber铆a ser algo simple y sencillo, y lo terminar谩 siendo, pero a d铆a de hoy clonar objetos es complejo (no una vez lees art铆culos como 茅ste) y requiere

  1. que entiendas el concepto de referencia, y que sepas que en JavaScript todo se copia por referencia
  2. que memorices que JSON.stringify est谩 aqu铆 para ayudarte (si no tienes m茅todos en el objeto)

Nada m谩s sencillo que esto 馃榾

Dicho esto, la frase todo se copia por referencia es en realidad incorrecta, en JavaScript todo se pasa por valor, pero los valores de todo lo que no son primitivas contienen referencias con lo que es "como" si se pasasen referencias

Si quieres constatar lo dif铆cil que es explicar este tema, tienes esta pregunta de stack overflow para entretenerte

Puedes repasar todo el c贸digo comentado en el codepen de aqu铆 abajo

Qu茅 tal la entrada?
馃憣 Bien 馃檶馃檶
馃憤 Bien, pero algunas cosas podr铆an explicarse mejor 馃槵
馃し鈥嶁檪锔 Da por sentadas demasiadas cosas 馃槖
馃し鈥嶁檪锔 A ver, hay poca chicha 馃槵
馃し鈥嶁檪锔 Los ejemplos no son muy claros 馃檱鈥嶁檪锔
馃し鈥嶁檪锔 No se entiende, est谩 mal escrito 馃憥
鉁嶏笍 Hay errores, rev铆salo en cuanto puedas 馃檹

Newsletter de kuworking, un correo de tanto en cuanto

Quiz谩 te interese

Privacidad
by kuworking.com
[ 2020 >> kuworking ]