Skip to content
Skip to content
Menu
Info Cafe
Info Cafe

Copiar objetos en JavaScript

By admin on enero 10, 2021

Los objetos son los bloques fundamentales de JavaScript. Un objeto es una colección de propiedades, y una propiedad es una asociación entre una clave (o nombre) y un valor. Casi todos los objetos en JavaScript son instancias de Object que se encuentra en la parte superior de la cadena de prototipos.

Introducción

Como sabes, el operador de asignación no crea una copia de un objeto, sólo le asigna una referencia, veamos el siguiente código:

let obj = { a: 1, b: 2,};let copy = obj;obj.a = 5;console.log(copy.a);// Result // a = 5;

La variable obj es un contenedor para el nuevo objeto inicializado. La variable copy apunta al mismo objeto y es una referencia a ese objeto. Así que básicamente este objeto { a: 1, b: 2, } está diciendo: Ahora hay dos formas de acceder a mí. Tienes que pasar a través de la variable obj o de la variable copy de cualquier manera sigues llegando a mí y cualquier cosa que me hagas a través de estas formas (puertas de enlace) me afectará.

¡Se habla mucho de la inmutabilidad estos días y tienes que escuchar esta llamada! Este método elimina cualquier forma de inmutabilidad y podría dar lugar a errores en caso de que el objeto original sea utilizado por otra parte de tu código.

La forma ingenua de copiar objetos

La forma ingenua de copiar objetos es hacer un bucle a través del objeto original y copiar cada propiedad una tras otra. Echemos un vistazo a este código:

function copy(mainObj) { let objCopy = {}; // objCopy will store a copy of the mainObj let key; for (key in mainObj) { objCopy = mainObj; // copies each property to the objCopy object } return objCopy;}const mainObj = { a: 2, b: 5, c: { x: 7, y: 4, },}console.log(copy(mainObj));

Asuntos inherentes

  1. objCopy el objeto tiene un nuevo método Object.prototype diferente al método del prototipo del objeto mainObj, que no es lo que queremos. Queremos una copia exacta del objeto original.
  2. Los descriptores de propiedades no se copian. Un descriptor «escribible» con valor establecido como falso será verdadero en el objeto objCopy.
  3. El código anterior sólo copia las propiedades enumerables de mainObj.
  4. Si una de las propiedades del objeto original es un objeto en sí, entonces se compartirá entre la copia y el original haciendo que sus respectivas propiedades apunten al mismo objeto.

Copia superficial de objetos

Se dice que un objeto está copiado superficialmente cuando las propiedades de nivel superior del origen se copian sin ninguna referencia y existe una propiedad de origen cuyo valor es un objeto y se copia como referencia. Si el valor de origen es una referencia a un objeto, sólo se copia ese valor de referencia al objeto de destino.

Una copia superficial duplicará las propiedades de nivel superior, pero el objeto anidado se comparte entre el original(fuente) y la copia(destino).

Usando el método Object.assign()

El método Object.assign() se utiliza para copiar los valores de todas las propiedades propias enumerables de uno o varios objetos origen a un objeto destino.

let obj = { a: 1, b: 2,};let objCopy = Object.assign({}, obj);console.log(objCopy);// Result - { a: 1, b: 2 }

Bien, esto hace el trabajo hasta ahora. Hemos hecho una copia de obj. Veamos si existe la inmutabilidad:

let obj = { a: 1, b: 2,};let objCopy = Object.assign({}, obj);console.log(objCopy); // result - { a: 1, b: 2 }objCopy.b = 89;console.log(objCopy); // result - { a: 1, b: 89 }console.log(obj); // result - { a: 1, b: 2 }

En el código anterior, cambiamos el valor de la propiedad 'b' en el objeto objCopy a 89 y cuando registramos el objeto objCopy modificado en la consola, los cambios sólo se aplican a objCopy. La última línea de código comprueba que el objeto obj sigue intacto y no ha cambiado. Esto implica que hemos creado con éxito una copia del objeto fuente sin ninguna referencia a él.

Caída de Object.assign()

¡No tan rápido! Aunque hemos creado con éxito una copia y todo parece funcionar bien, ¿recuerdas que hablamos de la copia superficial? Veamos este ejemplo:

let obj = { a: 1, b: { c: 2, },}let newObj = Object.assign({}, obj);console.log(newObj); // { a: 1, b: { c: 2} }obj.a = 10;console.log(obj); // { a: 10, b: { c: 2} }console.log(newObj); // { a: 1, b: { c: 2} }newObj.a = 20;console.log(obj); // { a: 10, b: { c: 2} }console.log(newObj); // { a: 20, b: { c: 2} }newObj.b.c = 30;console.log(obj); // { a: 10, b: { c: 30} }console.log(newObj); // { a: 20, b: { c: 30} }// Note: newObj.b.c = 30; Read why..

¿Por qué obj.b.c = 30?

Bueno, eso es una trampa de Object.assign()Object.assign sólo hace copias superficiales. Tanto newObj.b como obj.b comparten la misma referencia al objeto porque no se hicieron copias individuales, sino que se copió una referencia al objeto. Cualquier cambio realizado en cualquiera de las propiedades del objeto se aplica a todas las referencias que utilizan el objeto. ¿Cómo podemos solucionar esto? Sigue leyendo… tenemos una solución en la siguiente sección.

Nota: Las propiedades en la cadena de prototipos y las propiedades no enumerables no pueden ser copiadas. Ver aquí:

let someObj = { a: 2,}let obj = Object.create(someObj, { b: { value: 2, }, c: { value: 3, enumerable: true, },});let objCopy = Object.assign({}, obj);console.log(objCopy); // { c: 3 }

  • someObj está en la cadena de prototipos de obj por lo que no se copiaría.
  • property b es una propiedad no enumerable.
  • property c tiene un descriptor de propiedad enumerable que le permite ser enumerable. Por eso se ha copiado.

Copia profunda de objetos

Una copia profunda duplicará todos los objetos que encuentre. La copia y el objeto original no compartirán nada, por lo que será una copia del original. Aquí está la solución al problema que encontramos usando Object.assign(). Vamos a explorar.

Usando JSON.parse(JSON.stringify(object));

Esto soluciona el problema que teníamos antes. ¡Ahora newObj.b tiene una copia y no una referencia! Esta es una forma de copiar en profundidad los objetos. Aquí tienes un ejemplo:

let obj = { a: 1, b: { c: 2, },}let newObj = JSON.parse(JSON.stringify(obj));obj.b.c = 20;console.log(obj); // { a: 1, b: { c: 20 } }console.log(newObj); // { a: 1, b: { c: 2 } } (New Object Intact!)

Inmutable: ✓

Pitfall

Desgraciadamente, este método no se puede utilizar para copiar métodos de objetos definidos por el usuario. Ver más abajo.

Copiar métodos de objetos

Un método es una propiedad de un objeto que es una función. En los ejemplos hasta ahora, no hemos copiado un objeto con un método. Vamos a intentarlo ahora y a utilizar los métodos que hemos aprendido para hacer copias.

let obj = { name: 'scotch.io', exec: function exec() { return true; },}let method1 = Object.assign({}, obj);let method2 = JSON.parse(JSON.stringify(obj));console.log(method1); //Object.assign({}, obj)/* result{ exec: function exec() { return true; }, name: "scotch.io"}*/console.log(method2); // JSON.parse(JSON.stringify(obj))/* result{ name: "scotch.io"}*/

El resultado muestra que Object.assign() se puede utilizar para copiar métodos mientras que JSON.parse(JSON.stringify(obj)) no se puede utilizar.

Copiar objetos circulares

Los objetos circulares son objetos que tienen propiedades que se referencian a sí mismos. Vamos a utilizar los métodos de copia de objetos que hemos aprendido hasta ahora para hacer copias de un objeto circular y ver si funciona.

Usando JSON.parse(JSON.stringify(object))

Probemos JSON.parse(JSON.stringify(object)):

// circular objectlet obj = { a: 'a', b: { c: 'c', d: 'd', },}obj.c = obj.b;obj.e = obj.a;obj.b.c = obj.c;obj.b.d = obj.b;obj.b.e = obj.b.c;let newObj = JSON.parse(JSON.stringify(obj));console.log(newObj); 

Aquí está el resultado:

JSON.parse(JSON.stringify(obj)) claramente no funciona para objetos circulares.

Usando Object.assign()

Probemos con Object.assign():

// circular objectlet obj = { a: 'a', b: { c: 'c', d: 'd', },}obj.c = obj.b;obj.e = obj.a;obj.b.c = obj.c;obj.b.d = obj.b;obj.b.e = obj.b.c;let newObj2 = Object.assign({}, obj);console.log(newObj2); 

Aquí está el resultado:

Object.assign() funciona bien para la copia superficial de objetos circulares pero no funcionaría para la copia profunda. Siéntete libre de explorar el circular object tree en la consola de tu navegador. Estoy seguro de que encontrarás un montón de trabajo interesante allí.

Usando elementos de propagación ( … )

ES6 ya tiene implementados elementos de reposo para la asignación de desestructuración de arrays y elementos de propagación para literales de arrays. Echa un vistazo a la implementación de elementos spread en un array aquí:

const array = ;const newArray = ;console.log(newArray);// Result // 

La propiedad spread para literales de objetos es actualmente una propuesta de la fase 3 de ECMAScript. Las propiedades de propagación en los inicializadores de objetos copian las propiedades enumerables propias de un objeto de origen en el objeto de destino. El siguiente ejemplo muestra lo fácil que sería copiar un objeto una vez que la propuesta haya sido aceptada.

let obj = { one: 1, two: 2,}let newObj = { ...z };// { one: 1, two: 2 }

Nota: Esto sólo será efectivo para la copia superficial

Conclusión

Copiar objetos en JavaScript puede ser bastante desalentador especialmente si eres nuevo en JavaScript y no conoces el lenguaje. Esperemos que este artículo te haya ayudado a entender y a evitar futuros escollos que puedas encontrar copiando objetos. Si tienes alguna librería o pieza de código que logre un mejor resultado, siéntete bienvenido a compartirlo con la comunidad. Feliz codificación!

Navegación de entradas

Anuncio semanal de Kroger (24/21 – 3/2/21) y avance de anuncios de Kroger
Cómo hacer un CD/DVD/USB de arranque para instalar Windows

Deja una respuesta Cancelar la respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Entradas recientes

  • Firebush (Español)
  • 9 mejores vitaminas y suplementos para perros para mejorar su salud
  • Previsión de tasas de CD para 2021: Las tasas probablemente se mantendrán bajas, pero podrían aumentar más adelante en el año
  • Dolor pélvico crónico y prostatitis: síntomas, diagnóstico y tratamiento
  • Juegos y actividades saludables para niños | UIC Online Informatics
  • Cervezas de trigo (americanas)
  • Los beneficios de la lactancia materna después de un año
  • ¿Es seguro tirar los posos del café por el fregadero?
  • Enfriarse después de hacer ejercicio
  • Nuestro trabajo

Meta

  • Acceder
  • Feed de entradas
  • Feed de comentarios
  • WordPress.org

Archivos

  • marzo 2021
  • febrero 2021
  • enero 2021
  • diciembre 2020
  • DeutschDeutsch
  • NederlandsNederlands
  • EspañolEspañol
  • FrançaisFrançais
  • PortuguêsPortuguês
  • ItalianoItaliano
  • PolskiPolski
  • 日本語日本語
©2021 Info Cafe | WordPress Theme by SuperbThemes.com