debido a que los objetos en JavaScript son valores de referencia, no puede simplemente copiar usando el =
. Pero no te preocupes, aquí hay 3 formas de clonar un objeto
# los objetos son tipos de referencia
tu primera pregunta podría ser, ¿por qué no puedo usar=
. Vamos a ver qué pasa si hacemos eso:
const obj = { one: 1, two: 2 };const obj2 = obj;console.log( obj, // {one: 1, two: 2}; obj2, // {one: 1, two: 2};);
hasta ahora, ambos objetos parecen mostrar la misma salida. Así que no hay problema., Pero vamos a ver qué pasa si editamos nuestro segundo objeto:
const obj2.three = 3;console.log(obj2);// {one: 1, two: 2, three: 3}; <-- ✅console.log(obj);// {one: 1, two: 2, three: 3}; <-- 😱
WTH?! Cambié obj2
pero por qué fue obj
también afectado. Eso es porque los objetos son tipos de referencia. Así que cuando usa =
, copió el puntero al espacio de memoria que ocupa. Los tipos de referencia no contienen valores, son un puntero al valor en memoria.
si quieres aprender más sobre esto, echa un vistazo al curso Zhu Watch and Code de Gordon. Es gratis inscribirse y ver el video «comparación con objetos»., Él da una explicación súper impresionante en él.
# 1. Usando Spread
Usando spread clonará tu objeto. Tenga en cuenta que esta será una copia superficial. A partir de este post, el operador de propagación para la clonación de objetos se encuentra en la Etapa 4. Así que no está oficialmente en las especificaciones todavía. Así que si tuvieras que usar esto, tendrías que compilarlo con Babel (o algo similar).
const food = { beef: '🥩', bacon: '🥓' };const cloneFood = { ...food };console.log(cloneFood);// { beef: '🥩', bacon: '🥓' }
# 2. Usando Objeto.assign
alternativamente, Object.assign
está en el lanzamiento oficial y también creará una copia superficial del objeto.,
const food = { beef: '🥩', bacon: '🥓' };const cloneFood = Object.assign({}, food);console.log(cloneFood);// { beef: '🥩', bacon: '🥓' }
tenga en cuenta el vacío {}
como primer argumento, esto asegurará que usted no mutar el objeto original 👍
# 3. Usando JSON
esta forma final le dará una copia profunda. Ahora voy a mencionar, esta es una forma rápida y sucia de clonar profundamente un objeto. Para una solución más robusta, yo recomendaría el uso de algo como lodash
const food = { beef: '🥩', bacon: '🥓' };const cloneFood = JSON.parse(JSON.stringify(food));console.log(cloneFood);// { beef: '🥩', bacon: '🥓' }
# Lodash DeepClone vs JSON
Aquí un comentario de la comunidad. Sí, fue para mi post anterior, cómo clonar en profundidad una matriz ., Pero la idea todavía se aplica a los objetos.
Alfredo Salzillo: quiero que tenga en cuenta que hay algunas diferencias entre deepClone y JSON.stringify / parse.
- JSON.stringify / parse solo funciona con número y cadena y objeto literal sin propiedades de función o símbolo.
- deepclone trabajo con todos los tipos, función y símbolo se copian por referencia.
Este es un ejemplo:
@OlegVaraksin: el método JSON tiene problemas con las dependencias circulares. Además, el orden de las propiedades en el objeto clonado puede ser diferente.,
# shallow Clone vs Deep Clone
cuando utilicé spread ...
para copiar un objeto, solo estoy creando una copia superficial. Si la matriz está anidada o multidimensional, no funcionará. Este es nuestro ejemplo que usaremos:
const nestedObject = { flag: '🇨🇦', country: { city: 'vancouver', },};
# shallow Copy
clonemos nuestro objeto usando spread:
const shallowClone = { ...nestedObject };// Changed our cloned objectshallowClone.flag = '🇹🇼';shallowClone.country.city = 'taipei';
así que cambiamos nuestro objeto clonado cambiando la ciudad. Veamos la salida.
console.log(shallowClone);// {country: '🇹🇼', {city: 'taipei'}}console.log(nestedObject);// {country: '🇨🇦', {city: 'taipei'}} <-- 😱
una copia superficial significa que se copia el primer nivel, se hace referencia a los niveles más profundos.,
# Deep Copy
tomemos el mismo ejemplo pero aplicando una copia profunda usando «JSON»
Como puede ver, la copia profunda es una copia verdadera para objetos anidados. A menudo, la copia superficial del tiempo es lo suficientemente buena, realmente no necesita una copia profunda. Es como una pistola de clavos contra un martillo. La mayoría de las veces el martillo está perfectamente bien. El uso de una pistola de clavos para algunas pequeñas Artes y artesanías a menudo es un caso de exceso, un martillo está bien. Se trata de usar la herramienta correcta para el trabajo correcto
# Performance
Desafortunadamente, no puedo escribir una prueba para spread porque todavía no está oficialmente en la especificación., Sin embargo, lo incluí en la prueba para que puedas ejecutarlo en el futuro 😝. Pero el resultado muestra Object.assign
es mucho más rápido que el JSON
.
Prueba de Rendimiento
# Entrada de la Comunidad
# Objeto.assign vs Spread
@d9el: es importante tener en cuenta ese objeto.assign es una función que modifica y devuelve el objeto de destino. En Samantha ejemplo mediante la siguiente,
const cloneFood = Object.assign({}, food);
{}
es el objeto que se modifica., El objeto de destino no es referenciado por ninguna variable en ese momento, pero como Object.assign
devuelve el objeto de destino, podemos almacenar el objeto asignado resultante en la variable cloneFood
. Podemos cambiar nuestro ejemplo y uso de los siguientes:
const food = { beef: '🌽', bacon: '🥓' };Object.assign(food, { beef: '🥩' });console.log(food);// { beef: '🥩', bacon: '🥓' }
Obviamente, el valor de beef
en nuestra comida objeto es incorrecto, por lo que puede asignar el valor correcto de beef
con Object.assign
., En realidad no estamos usando el valor devuelto de la función en absoluto, pero estamos modificando nuestro objeto de destino al que hemos hecho referencia con el const food
.
Spread por otro lado es un operador que copia las propiedades de un objeto en un nuevo objeto., Si queremos replicar el ejemplo anterior usando spread para modificar nuestra variable food...
const food = { beef: '🌽', bacon: '🥓' };food = { ...food, beef: '🥩',};// TypeError: invalid assignment to const `food'
...
obtenemos un error, porque usamos spread al crear nuevos objetos, y por lo tanto estamos asignando un objeto completamente nuevo a food
que fue declarado con const
, que es ilegal., Así que podemos elegir para declarar una nueva variable para celebrar nuestro nuevo objeto, como la siguiente:
const food = { beef: '🌽', bacon: '🥓' };const newFood = { ...food, beef: '🥩',};console.log(newFood);// { beef: '🥩', bacon: '🥓' }
o, podemos declarar food
let
o var
que nos permita asignar un nuevo objeto:
let food = { beef: '🌽', bacon: '🥓' };food = { ...food, beef: '🥩',};console.log(food);// { beef: '🥩', bacon: '🥓' }
Gracias: @d9el
# Profundo Clonar el uso de Librerías Externas
# Más Formas de usar JavaScript
- @hariharan_d3v :
Object.fromEntries(Object.entries(food))
clones de los objetos.
Deja una respuesta