Tengo un problema realmente extraño, déjame explicarte:
Obj1: DetailsType = {property1: 123, property2: [{subProp1: 'a', subProp2: 'b'}]} Obj2: DetailsType = new DetailsType(Obj1)
Este es el constructor de DetailsType:
constructor(value: DetailsType = <DetailsType>{}){ this.property1 = (value.property1 !== undefined) ? value.property1 : null this.property2 = (value.property2 !== undefined) ? value.property2 : [] }
Ahora ejecuto el siguiente código
this.Obj2.property1 = 987 this.Obj2.property2[0].subProp1 = 'z'
En este punto, por alguna razón, el valor de Obj1.property2[0].subProp1 is 'z'
Aunque cambiamos el valor de subProp1
para Obj2! Sin embargo, Obj1.property1 is still 123
Entonces, ¿por qué cambiar property2
que es una matriz, afecta el valor de ambos objetos? ¿Cómo puede property1
, un número, funcionar correctamente, pero property2
funciona de manera tan extraña? Funciona a la inversa, ya sea que cambie subProp1 por Obj1 u Obj2. Estoy tan confundida.
¡Gracias por tu ayuda!
Está sucediendo porque value.property2
es un objeto con muchas referencias anidadas a otros objetos dentro de él. Necesita clonar en profundidad el value.property2
en el constructor:
class DetailsType { constructor(value) { this.prop1 = (value.prop1 !== undefined) ? value.prop1 : null this.prop2 = (value.prop2 !== undefined) ? JSON.parse(JSON.stringify(value.prop2)) : [] } } let obj1 = { prop1: 123, prop2: [{ subProp1: 'a', subProp2: 'b' }] }; let obj2 = DetailsType = new DetailsType(obj1); obj2.prop1 = 987 obj2.prop2[0].subProp1 = 'z' document.body.innerHTML += `obj1:<pre>${JSON.stringify(obj1, undefined, 2)}</pre>`; document.body.innerHTML += `obj2:<pre>${JSON.stringify(obj2, undefined, 2)}</pre>`;
Para conocer varias formas de clonación profunda de objetos, consulte:
La respuesta actual (con JSON.stringify
) quizás no sea la peor, porque funcionará en este caso. Pero no sabemos cómo se verán realmente sus objetos en la matriz de prop2
. Debido a que es una clase de TypeScript, podría ser que también le agregue algunos métodos. Sin embargo, con JSON.stringify
, todos los métodos/funciones se perderían. Solo se conservan las propiedades de valor, pero tampoco en el orden correcto. El resultado es solo un objeto anónimo.
Debido a que a veces es necesario clonar objetos (y no tener sus propiedades referenciadas al objeto original), es bastante útil agregar una función .clone()
que se puede usar con cada objeto y matriz.
Esto funcionará simplemente agregando el siguiente código:
(<any>Object.prototype).clone = function() { const clone = (this instanceof Array) ? [] : {}; for (const propertyName in this) { if (propertyName == 'clone') continue; if (this[propertyName] && typeof this[propertyName] == "object") { clone[propertyName] = this[propertyName].clone(); } else clone[propertyName] = this[propertyName] } return clone; };
Con su código dado, se verá así (bastante limpio):
class DetailsType { public prop1; public prop2; constructor(value) { this.prop1 = value.prop1 !== undefined ? value.prop1 : null; this.prop2 = value.prop2 !== undefined ? value.prop2.clone() : []; } }
El método .clone()
funciona tanto para matrices como para objetos y creará una copia profunda.