Copiar objetos en JS

Ana Martínez Aguilar
3 min readApr 30, 2018

--

A diferencia de los datos primitivos (string, number…), los objetos en JavaScript se copian por referencia. Cuando a una variable le asignamos un objeto ya creado anteriormente, en realidad no estamos haciendo una copia del valor idéntico de este objetos, si no que estamos apuntando a él. Es lo que se conoce como copia por referencia, y también se aplica en otros casos, como con los arrays y las funciones.

La consecuencia de este tipo de copia es que si modificamos el objeto, estaremos modificando también la copia (modificar a través de sus propiedades, no reasignar).

Tengo este objeto:

const originalObject = {
name: ‘Ada’,
surname: “Lovelace”
};

Hago una “copia”:

const newObject = originalObject;console.log(newObject)
// → {name: “María”, surname: “Molina”}

Modifico el objeto original:

originalObject.name = “Celia”console.log(newObject);
// → {name: “Celia”, surname: “Molina”}

Como se puede ver con el ejemplo, si modifico el objeto original, también se modifica el objeto copiado. Lo mismo sucede al revés:

newObject.surname = “Martínez”;console.log(originalObject);
// → {name: “Celia”, surname: “Martínez”}

Object.assign(obj)

¿Cómo podemos tener una copia independiente de un objeto? Hay varias formas de copiar un objeto y no tener qué preocuparnos de que uno de los objetos se modifique y afecte al otro.

Una opción es utilizar el método Object.assign(obj).

const originalObject = {
name: “María”,
surname: “Molina”
};
const newObject = Object.assign({}, originalObject);originalObject.name = “Celia”;console.log(newObject);
// → {name: “María”, surname: “Molina”}

Con este ejemplo vemos que aunque cambiemos uno de los objetos, no afecta al otro.

También podemos añadir nuevas propiedades a la copia con este método.

const originalObject = {
name: “María”,
surname: “Molina”
};const newObject = Object.assign({}, originalObject, { city: “Madrid”, age: 34 });console.log(newObject);
// → {name: “María”, surname: “Molina”, city: “Madrid”, age: 34}

Copia profunda

El método Object.assign() no es válido por sí solo para todo tipo de situaciones. Así, este método no copia por valor los objetos en niveles inferiores, sino que los objetos de niveles inferiores se copian por referencia.

En este ejemplo, el objeto originalObject encierra otro objeto en una de sus propiedades. En este caso, el método Object.assign() no se aplica a este segundo objeto.

const originalObject = {
name: “María”,
surname: “Molina”,
location: {
city: “Madrid”,
street: “Gran Vía”
}
};
const newObject = Object.assign({}, originalObject);originalObject.location.city = "Bilbao";console.log(originalObject.location);
// → city: "Bilbao", street: "Gran Vía"
console.log(newObject.location);
// → city: "Bilbao", street: "Gran Vía"

Hay varias formas de solucionar esto. Una de ellas es convertir todo el objeto a string, para que copie por valor y no por referencia, y luego volver a convertirlo a un objeto. Sin embargo, este método se quedaría corto en ciertos casos, puesto que genera problemas al copiar valores más complejos como funciones.

Para realizar copias profundas de objetos, una solución más certera es utilizar la iteración y/o la recursividad.

En el siguiente ejemplo, creo un bucle for in para recorrerme todas las propiedades del objeto original y voy añadiendo al nuevo objeto las propiedades del objeto original.

Cuando el valor de una de las propiedades es un objeto, vuelvo a llamar a la función clonadora para que añada también las propiedades de ese objeto que se encuentra en un nivel inferior. Si no es un objeto, simplemente añado la propiedad.

function deepClone(originalObject) {
const clonedObject = {};
for (var key in originalObject) {
if (typeof (originalObject[key]) != “object”) {
clonedObject[key] = originalObject[key];
} else {
clonedObject[key] = deepClone(originalObject[key]);
}
}
return clonedObject;
}
const newObject = deepClone(originalObject);originalObject.location.city = “Bilbao”;console.log(newObject.location);
// → {city: “Madrid”, street: “Gran Vía”}

--

--