¿Cómo clono una instancia de clase Javascript usando ES6?
No estoy interesado en soluciones basadas en jquery o $ extend.
He visto discusiones bastante antiguas sobre la clonación de objetos que sugieren que el problema es bastante complicado, pero con ES6 se presenta una solución muy simple: la pondré a continuación y veré si la gente piensa que es satisfactoria.
editar: se sugiere que mi pregunta es un duplicado; Vi esa respuesta, pero tiene 7 años e involucra respuestas muy complicadas usando js pre-ES6. Estoy sugiriendo que mi pregunta, que permite ES6, tiene una solución dramáticamente más simple.
Object
s puros utilizados como contenedores de datos. Este es sobre ES6class
es y el problema de no perder la información del tipo de clase. Necesita una solución diferente.Respuestas:
Es complicado; ¡Intenté mucho! Al final, esta frase funcionó para mis instancias de clase ES6 personalizadas:
let clone = Object.assign(Object.create(Object.getPrototypeOf(orig)), orig)
Evita configurar el prototipo porque dicen que ralentiza mucho el código.
Admite símbolos, pero no es perfecto para captadores / definidores y no funciona con propiedades no enumerables (consulte los documentos de Object.assign () ). Además, la clonación de clases internas básicas (como Array, Date, RegExp, Map, etc.), lamentablemente, a menudo parece necesitar un manejo individual.
Conclusión: es un desastre. Esperemos que algún día haya una funcionalidad de clonación nativa y limpia.
fuente
const clone = Object.assign( {}, instanceOfBlah ); Object.setPrototypeOf( clone, Blah.prototype );
Tenga en cuenta las características de Object.assign : realiza una copia superficial y no copia métodos de clase.
Si desea una copia profunda o más control sobre la copia, existen las funciones de clonación lodash .
fuente
Object.create
crea un nuevo objeto con un prototipo especificado, ¿por qué no simplementeconst clone = Object.assign(Object.create(instanceOfBlah), instanceOfBlah)
. También se copiarán los métodos de clase.Blah.prototype != instanceOfBlah
. Deberías usarObject.getPrototypeOf(instanceOfBlah)
No se recomienda hacer extensiones del prototipo, dará lugar a problemas cuando realice pruebas en su código / componentes. Los marcos de prueba unitarios no asumirán automáticamente sus extensiones de prototipo. Entonces no es una buena práctica. Hay más explicaciones sobre las extensiones de prototipos aquí. ¿Por qué es una mala práctica extender objetos nativos?
Para clonar objetos en JavaScript no existe una forma simple o directa. Aquí está la primera instancia que usa "Copia superficial":
1 -> Clon superficial:
class Employee { constructor(first, last, street) { this.firstName = first; this.lastName = last; this.address = { street: street }; } logFullName() { console.log(this.firstName + ' ' + this.lastName); } } let original = new Employee('Cassio', 'Seffrin', 'Street A, 23'); let clone = Object.assign({},original); //object.assing() method let cloneWithPrototype Object.create(Object.getPrototypeOf(original)), original) // the clone will inherit the prototype methods of the original. let clone2 = { ...original }; // the same of object assign but shorter sintax using "spread operator" clone.firstName = 'John'; clone.address.street = 'Street B, 99'; //will not be cloned
Resultados:
Aviso: si la instancia tiene cierres como propiedades propias, este método no la ajustará. ( lea más sobre cierres ) Y además, el subobjeto "dirección" no será clonado.
no trabajará.
funcionará, porque el clon también copiará sus Prototipos.
Para clonar matrices con Object.assign:
let cloneArr = array.map((a) => Object.assign({}, a));
Clonar matriz usando ECMAScript spread sintax:
let cloneArrSpread = array.map((a) => ({ ...a }));
2 -> Clon profundo:
Para archivar una referencia de objeto completamente nueva, podemos usar JSON.stringify () para analizar el objeto original como una cadena y luego volver a analizarlo en JSON.parse ().
let deepClone = JSON.parse(JSON.stringify(original));
Con la clonación profunda se mantendrán las referencias a la dirección. Sin embargo, los prototipos deepClone se perderán, por lo que deepClone.logFullName () no funcionará.
3 -> Bibliotecas de terceros:
Otras opciones serán utilizar bibliotecas de terceros como loadash o subrayado. Crearán un nuevo objeto y copiarán cada valor del original al nuevo objeto manteniendo sus referencias en la memoria.
Guión bajo: deje cloneUnderscore = _ (original) .clone ();
Clon de carga: var cloneLodash = _.cloneDeep (original);
La desventaja de lodash o subrayado fue la necesidad de incluir algunas bibliotecas adicionales en su proyecto. Sin embargo, son buenas opciones y también producen resultados de alto rendimiento.
fuente
{}
, el clon no heredará ninguno de los métodos prototipo del original.clone.logFullName()
no funcionará en absoluto. LoObject.assign( Object.create(Object.getPrototypeOf(eOriginal)), eOriginal)
que tenías antes estaba bien, ¿por qué lo cambiaste?Object.assign({},original)
que, no funciona.Otro trazador de líneas:
La mayoría de las veces ... (funciona para Date, RegExp, Map, String, Number, Array), por cierto, la cadena de clonación, el número es un poco divertido.
let clone = new obj.constructor(...[obj].flat())
para aquellas clases sin constructor de copia:
let clone = Object.assign(new obj.constructor(...[obj].flat()), obj)
fuente
class A { constructor() { this.x = 1; } y() { return 1; } } const a = new A(); const output = Object.getOwnPropertyNames(Object.getPrototypeOf(a)).concat(Object.getOwnPropertyNames(a)).reduce((accumulator, currentValue, currentIndex, array) => { accumulator[currentValue] = a[currentValue]; return accumulator; }, {});
fuente
Puede usar el operador de propagación, por ejemplo, si desea clonar un objeto llamado Obj:
let clone = { ...obj};
Y si desea cambiar o agregar algo al objeto clonado:
let clone = { ...obj, change: "something" };
fuente