Reputation: 141
I have a really weird problem, let me just explain:
Obj1: DetailsType = {property1: 123, property2: [{subProp1: 'a', subProp2: 'b'}]}
Obj2: DetailsType = new DetailsType(Obj1)
This is the constructor of DetailsType:
constructor(value: DetailsType = <DetailsType>{}){
this.property1 = (value.property1 !== undefined) ? value.property1 : null
this.property2 = (value.property2 !== undefined) ? value.property2 : []
}
Now I run the following code
this.Obj2.property1 = 987
this.Obj2.property2[0].subProp1 = 'z'
At this point, for some reason, the value of Obj1.property2[0].subProp1 is 'z'
Even though we changed the value of subProp1
for Obj2! However, Obj1.property1 is still 123
So why does changing property2
which is an array, affect the value on both objects?? How can property1
, a number, work correctly, but property2
work so weirdly? It works vice versa, whether I change subProp1 for Obj1 or Obj2. I'm so confused.
Thanks for your help!
Upvotes: 0
Views: 131
Reputation: 1386
The current answer (with JSON.stringify
) is maybe not the worst, because it will work in this case. But we don't know, how your objects in the array of prop2
will actually look like. Because it is a TypeScript class, it could be, that you also add some methods to it. With JSON.stringify
though, all methods/functions would be lost. Only the value-properties are retained, but also not in the right order. The result is just some anonymous object.
Because it is sometimes necessary to clone objects (and not have their properties referenced to the original object), it is pretty useful to add a .clone()
function that can be used with every object and array.
This will work by just adding the following code:
(<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;
};
With your given code, it will look like this (pretty clean):
class DetailsType {
public prop1;
public prop2;
constructor(value) {
this.prop1 = value.prop1 !== undefined ? value.prop1 : null;
this.prop2 = value.prop2 !== undefined ? value.prop2.clone() : [];
}
}
The .clone()
method works both for arrays and objects and will create a deep copy.
Upvotes: 1
Reputation: 18408
It is happening because the value.property2
is an object with many nested references to other objects inside it. You need to deep clone the value.property2
in the 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>`;
To find out various ways of deep cloning objects refer:
Upvotes: 2