Breaking

Post Top Ad

Your Ad Spot

viernes, 14 de junio de 2019

Cómo copiar objetos en JavaScript

Introducción

Una tarea muy común en la programación, independientemente del lenguaje, es copiar (o clonar) un objeto por valor, en lugar de copiar por referencia. La diferencia es que al copiar por valor, tiene dos objetos no relacionados con el mismo valor o datos. Copiar por referencia significa que tiene dos objetos que apuntan a los mismos datos en la memoria. Esto significa que si manipula el objeto A, por ejemplo, también manipulará el objeto B, ya que ambos hacen referencia a los mismos datos subyacentes.
En este artículo repasaré algunas de las formas en que puede copiar objetos por valor en JavaScript. Mostraré cómo puede hacerlo utilizando bibliotecas de terceros y escribiendo su propia función de copia.
Nota : dado que Node.js es solo un tiempo de ejecución creado en el motor V8 de JavaScript, todos los métodos de clonación que muestro en este artículo también funcionarán para Node.

Bibliotecas de terceros

Hay varias bibliotecas de terceros populares que tienen esta funcionalidad incorporada, que veremos en las siguientes secciones. En mi opinión, esta es la mejor solución para la mayoría de los casos de uso simples, ya que han sido probados y actualizados continuamente. Escribir este tipo de código usted mismo no es fácil, por lo que es muy útil poder usar un código que tenga muchos ojos en él.

Lodash

La biblioteca de Lodash proporciona algunos métodos diferentes para copiar o clonar objetos, dependiendo de su caso de uso.
El método más genérico es el clone()método, que proporciona copias superficiales de objetos. Funciona simplemente pasando el objeto como primer argumento, y la copia será devuelta:
const _ = require('lodash');

let arrays = {first: [1, 2, 3], second: [4, 5, 6]};  
let copy = _.clone(arrays);  
console.log(copy);  
{ first: [ 1, 2, 3 ], second: [ 4, 5, 6 ] }
Esto significa que el objeto de "nivel superior" (o matriz, búfer, mapa, etc.) se clona, ​​pero cualquier objeto más profundo se copiará por referencia. El siguiente código demuestra que la firstmatriz en el arraysobjeto original es el mismo objeto que la firstmatriz en el copyobjeto:
const _ = require('lodash');

let arrays = {first: [1, 2, 3], second: [4, 5, 6]};  
let copy = _.clone(arrays);  
console.log(copy.first === arrays.first);  
true  
Si prefiere que todos los objetos, tanto los objetos poco profundos como los profundos, se copien, entonces querrá usar el cloneDeep()método:
const _ = require('lodash');

let arrays = {first: [1, 2, 3], second: [4, 5, 6]};  
let copy = _.cloneDeep(arrays);  
console.log(copy);  
{ first: [ 1, 2, 3 ], second: [ 4, 5, 6 ] }
Este método funciona mediante la clonación recursiva de todos los valores en cualquier nivel de profundidad.
Al ejecutar la misma verificación de igualdad desde arriba, podemos ver que las matrices originales y las copiadas ya no son iguales, ya que son copias únicas:
const _ = require('lodash');

let arrays = {first: [1, 2, 3], second: [4, 5, 6]};  
let copy = _.cloneDeep(arrays);  
console.log(copy.first === arrays.first);  
false  
Lodash ofrece algunos métodos de clonación más, incluyendo cloneWith()cloneDeepWith()Ambos métodos aceptan otro parámetro llamado customizer, que es una función que se utiliza para ayudar a producir el valor copiado.
Entonces, si desea utilizar alguna lógica de copia personalizada, puede pasar una función para manejarla dentro del método de Lodash. Por ejemplo, supongamos que tiene un objeto que contiene algunos Dateobjetos, pero desea que esos se conviertan en marcas de tiempo al copiarse, podría hacerlo así:
const _ = require('lodash');

let tweet = {  
    username: '@ScottWRobinson',
    text: 'I didn\'t actually tweet this',
    created_at: new Date('December 21, 2018'),
    updated_at: new Date('January 01, 2019'),
    deleted_at: new Date('February 28, 2019'),
};
let tweetCopy = l.cloneDeepWith(tweet, (val) => {  
    if (l.isDate(val)) {
        return val.getTime();
    }
});
console.log(tweetCopy);  
{ username: '@ScottWRobinson',
  text: 'I didn\'t actually tweet this',
  created_at: 1545372000000,
  updated_at: 1546322400000,
  deleted_at: 1551333600000 }
Como puede ver, los únicos datos que se modificaron con nuestro método fueron los Dateobjetos, que ahora se han convertido en las marcas de tiempo de Unix.

Guion bajo

El subrayado clone() método funciona casi de la misma manera que Lodash del clone()método. Solo proporciona una copia superficial del objeto dado, con cualquier objeto anidado que se copia por referencia.
El mismo ejemplo que antes demuestra esto:
const _ = require('underscore');

let arrays = {first: [1, 2, 3], second: [4, 5, 6]};  
let copy = _.clone(arrays);  
console.log(copy.first === arrays.first);  
true  
Desafortunadamente, la biblioteca de guiones bajos no parece tener ningún método para manejar la copia profunda. Puede implementar esta lógica por su cuenta (utilizando parte de la lógica que se muestra a continuación) y aún así utilizar el clonemétodo de los guiones bajos para la copia superficial, o puede probar una de las otras soluciones en este artículo.

Soluciones personalizadas

Como mencioné anteriormente, asumir este desafío por sí mismo es difícil, ya que hay muchos casos (y casos difíciles) que se deben manejar al clonar un objeto en JavaScript. Aunque, si se hace correctamente, podrá agregar una personalización agradable dentro de su método que de otra forma no sería posible.

Usando Métodos JSON

Una solución a menudo citada es simplemente usar los métodos JSON.stringifyJSON.parsepara su ventaja, como esto:
let arrays = {first: [1, 2, 3], second: [4, 5, 6]};  
let copy = JSON.parse(JSON.stringify(arrays));  
console.log(copy);  
{ first: [ 1, 2, 3 ], second: [ 4, 5, 6 ] }
Esto te dejará con un objeto profundamente copiado, y funciona muy bien para los objetos simples que se convierten fácilmente a JSON.
Nuevamente podemos verificar esto usando el mismo cheque que el de arriba:
console.log(copy.first === arrays.first);  
false  
Si sabe que su objeto es fácilmente serializable, entonces esta podría ser una buena solución para usted.

Escribiendo tu propio desde cero

Si, por alguna razón, ninguna de las otras soluciones funciona para usted, tendrá que escribir su propio método de clonación.
Como no confío en mí mismo para implementar correctamente un método de clonación completa (y arriesgo a los lectores que copian mis errores en su código de producción), he copiado la siguiente función de clonación de esta esencia , que copia objetos de forma recursiva y parece funcionar en muchos de los tipos de datos comunes que ejecutará en JavaScript.
function clone(thing, opts) {  
    var newObject = {};
    if (thing instanceof Array) {
        return thing.map(function (i) { return clone(i, opts); });
    } else if (thing instanceof Date) {
        return new Date(thing);
    } else if (thing instanceof RegExp) {
        return new RegExp(thing);
    } else if (thing instanceof Function) {
        return opts && opts.newFns ? new Function('return ' + thing.toString())() : thing;
    } else if (thing instanceof Object) {
        Object.keys(thing).forEach(function (key) { newObject[key] = clone(thing[key], opts); });
        return newObject;
    } else if ([ undefined, null ].indexOf(thing) > -1) {
        return thing;
    } else {
        if (thing.constructor.name === 'Symbol') {
            return Symbol(thing.toString().replace(/^Symbol\(/, '').slice(0, -1));
        }
        return thing.__proto__.constructor(thing);
    }
}
Esta función funciona mediante el manejo de casos específicos cuando es necesario (como matrices, expresiones regulares, funciones, etc.), y luego, para todos los demás tipos de datos (como números, cadenas, booleanos, etc.), utiliza por defecto el thingpropio constructor para copiar. el valor. Si el thinges un objeto en sí mismo, entonces solo se llama a sí mismo recursivamente en los atributos secundarios de thing.
Consulte la información completa en el enlace de arriba para ver todos los tipos de datos y casos de borde en los que se ha probado.

Conclusión

Aunque simple en teoría, en la práctica, copiar un objeto en JavaScript no es nada simple. Afortunadamente, existen bastantes soluciones para que las utilices, como cloneDeepen Lodash, o incluso los JSONmétodos integrados Y si por alguna razón ninguno de ellos es adecuado, entonces es posible escribir su propio método de clonación, siempre y cuando lo pruebe a fondo.

No hay comentarios.:

Publicar un comentario

Dejanos tu comentario para seguir mejorando!

Post Top Ad

Your Ad Spot

Páginas