Copiar un object
es algo que cuando queremos hacerlo es porque queremos una copia idéntica del objeto, pero independiente
Esa independencia no es fácil de conseguir porque lo que copiaremos serán referencias a variables, cuando lo que querríamos sería crear nuevas variables con los mismos valores
Para escenificarlo mira este código
let myVar = 'hola'
let myVar2 = myVar
myVar = 'que tal'
console.log(myVar) // que tal
console.log(myVar2) // hola
Aquí pasan 2 cosas
- Cuanodo asignamos una variable primita a otra variable primitiva, nunca se asignan referencias, siempre se asignan valores, con lo que
myVar2
nunca contendrá una referencia amyVar
, sino el valor que tenía en ese momento - Cuando hacemos la segunda asignación
myVar = 'que tal'
, no estamos cambiando el valor delstring
que tenía la sino que estamos creando una nueva variable de tipostring
En cambio, si utilizamos cualquier estructura de datos (esto es, un valor no primitivo)
let myVar = ['hola']
let myVar2 = myVar
myVar[0] = 'que tal'
console.log(myVar) // ['que tal']
console.log(myVar2) // ['que tal']
Aquí vuelven a pasar dos cosas
- Aquí
myVar2
sí que guarda la referencia demyVar
, en lugar de almacenar su valor - Y con la segunda asignación
myVar[0] = 'que tal'
aquí no estamos creando una nueva variablemyVar
sino que estamos modificando la variable
Esa variable myVar[0]
sí que la estamos creando de nuevo, pero myVar
se mantiene siendo la misma que la original
Entonces, la pregunta es, cómo puedo copiar estructuras y valores todo a la vez?
- Copia simple
let myObj = { site: 'https://kuworking.github.io/' }
console.log(myObj.site) // https://kuworking.github.io/
let myObjCopy = myObj
console.log(myObjCopy.site) // https://kuworking.github.io/
myObj.site = 'https://www.mevoyaotropiso.com'
console.log(myObj.site) // https://www.mevoyaotropiso.com
console.log(myObjCopy.site) // https://www.mevoyaotropiso.com
- Copia shallow (superficial)
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
let myObj = {
site: 'https://kuworking.github.io/',
data: {
type: 'blog',
location: 'barcelona',
},
}
let myObjCopy = Object.assign({}, myObj)
myObjCopy.site = 'https://www.mevoyaotropiso.com'
myObjCopy.data.type = 'mudanza'
console.log(myObj)
console.log(myObjCopy)
/*
{
"site": "https://kuworking.github.io/", >___> NO ha cambiado
"data": {
"type": "mudanza", >>>>> ha cambiado
"location": "barcelona"
}
}
{
"site": "https://www.mevoyaotropiso.com", >>>>> ha cambiado
"data": {
"type": "mudanza", >>>>> ha cambiado
"location": "barcelona"
}
}
*/
- 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
Soluciones hay varias, desde hacer un loop
recursivo hasta hacer lo que haremos en unas líneas
La primera opción te da la posibilidad de hacer una copia perfecta, incluyendo los métodos que pudieras tener en el objeto
Podrías hacerlo vía librería tipo loadash
o fabricándote una función tu mismo
O puedes hacer lo siguiente:
- convertir el objeto a texto, y luego volver a convertir el texto en objeto
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
Excepto los métodos, estos se pierden (si es que tienes)
Se hace con JSON.stringify
y JSON.parse
let myObj = {
site: 'https://kuworking.github.io/',
data: {
type: 'blog',
location: 'barcelona',
},
}
let myObjCopy = JSON.parse(JSON.stringify(myObj))
myObjCopy.site = 'https://www.mevoyaotropiso.com'
myObjCopy.data.type = 'mudanza'
console.log(myObj)
console.log(myObjCopy)
/*
{
"site": "https://kuworking.github.io/",
"data": {
"type": "blog",
"location": "barcelona"
}
}
{
"site": "https://www.mevoyaotropiso.com",
"data": {
"type": "mudanza",
"location": "barcelona"
}
}
*/
Y efectivamente, ahora he cambiado todo el objeto-copia sin alterar el objeto-original
Si quieres intentar entender mejor si las variables en JavaScript se pasan por valor o por referencia puedes entretenerte con los comentarios en stack overflow
En realidad siempre se pasan por valor, pero ese valor puede almacenar un (valor) primitivo o una referencia