Class A is instantiated to an object that has an array named this.people
that is filled with a bunch of data. Class A instantiates an object of class B and this.people
is passed to it's constructor. If object B updates the array, when object A updates it, it overwrites the changes from object B. How can I fix this?

- 673
- 2
- 6
- 21
-
So you want class B to have a reference to a copy of the array rather than to the original? – Brett Jeffreson Jan 19 '20 at 22:53
-
When you update the array, don't assume it's how you last left it, since you're sharing the reference. – Patrick Roberts Jan 19 '20 at 22:55
3 Answers
That happens because you're passing a reference of A's people
array to B's constructor. You want to make either a "shallow copy" or a "deep copy" of A's people
array, since you want B's people
array contents to be different.
With a "shallow copy" you copy all of the primitive values in the array to the new one, but if you have compound values (arrays or objects) inside the array, then only the reference to them will be copied, so any changes that you do to the compound values will be reflected in both A and B. With a "deep copy", both primitive and compound values (and not just their references) will be copied to a new place in memory.
If you don't have objects and arrays inside the people
array, you can do a shallow copy using Array.from(a.people)
. Otherwise, you can do a deep copy with JSON.parse(JSON.stringify(a.people))
Snippet:
class B {
constructor(_people) {
// shallow copy:
this.people = Array.from(_people);
// deep copy:
//this.people = JSON.parse(JSON.stringify(_people));
}
}
class A {
constructor() {
this.people = [];
}
func() {
this.objB = new B(this.people);
//do something
}
}
// Usage Example
let objA = new A();
objA.people.push("A");
objA.func();
objA.objB.people.push("B");
console.log(objA.people.toString());
console.log(objA.objB.people.toString());
Some helpful links: https://medium.com/@gamshan001/javascript-deep-copy-for-array-and-object-97e3d4bc401a
https://dev.to/samanthaming/how-to-deep-clone-an-array-in-javascript-3cig

- 315
- 4
- 12
-
From OPs description, it sounded more like they were not doing any copy at all, and a shallow one would have sufficed. – Bergi Jan 19 '20 at 23:13
-
@Bergi What I understood is that he does not want A's changes to overwrite B's changes, so they need to be different arrays in memory. Will's answer does a deep copy in an interesting way that should be faster than using JSON though, kudos to him. ^^ – MangaD Jan 19 '20 at 23:21
-
@Will doesn't do a deep (or shallow) copy at all, he just nests the array in a new array. The `wilsons.people` are an array of arrays (or later, an array of an array and a string). This is not desirable. – Bergi Jan 19 '20 at 23:26
-
@Bergi You're right, I didn't notice that. I suppose `JSON.parse` and `JSON.stringify` are the way to go. – MangaD Jan 19 '20 at 23:45
-
A simple `people.slice()`, `Array.from(people)` or `[...people]` would most likely have sufficed – Bergi Jan 19 '20 at 23:49
-
@Bergi Ah, I see. It will depend on whether he has an object inside the array or not. Because if he does, then changes to the object will be reflected in both arrays, since only references are copied. – MangaD Jan 20 '20 at 00:00
-
Indeed. But without the OP having shown any code, it's pointless to discuss :-) – Bergi Jan 20 '20 at 00:11
Give each class its own version of people
class A{
constructor(){
this.people = ["bob","jane","john"]
this.objB = new B(this.people)
}
}
class B{
constructor(people){
this.people = people
}
}
let objA = new A()
objA.objB.people.push("a")
objA.people.push("b")
console.log(objA.people, objA.objB.people)

- 11,687
- 7
- 53
- 122

- 11,984
- 7
- 29
- 50
-
Now where in your code is the "own version"? The snippet demonstrates exactly the undesired behaviour. – Bergi Jan 19 '20 at 23:11
-
@Bergi he says "If object B updates the array, when object A updates it, it overwrites the changes from object B." My "own version" fixes this. – symlink Jan 19 '20 at 23:14
-
Your code does not construct an "own version" anywhere. It uses the same array in both objects, and the log shows that `a` and `b` appear in the (same) array on both objects. – Bergi Jan 19 '20 at 23:18
-
Pass the array by value with destructuring.
class Family {
constructor(people) {
this.people = people;
}
}
let members = ["mom", "dad"];
let smiths = new Family(members);
let joneses = new Family(smiths.people); // pass by reference
joneses.people.push("Billy");
console.log(smiths.people); // changes to ["mom","dad","Billy"]
let wilsons = new Family([...smiths.people]); // pass by value
wilsons.people.push("Suzy");
console.log(smiths.people); // remains ["mom","dad","Billy"]

- 3,201
- 1
- 19
- 17
-
-
`let wilsons = new Family([smiths.people]);` The brackets destructure the array into a new array. – Will Jan 20 '20 at 18:36
-
No, they don't. Destructuring includes a lefthand-side value, e.g. an assignment target or a parameter definition. You just construct an array containing another array. – Bergi Jan 20 '20 at 18:37
-
-
It's an array literal. But it doesn't even give the correct result (try logging `wilsons.people` instead of logging `smiths.people` again), maybe you meant something else? – Bergi Jan 20 '20 at 18:41
-
I meant smiths.people to show that updating wilsons doesn't affect smiths. – Will Jan 20 '20 at 18:43
-
Yes, but `wilsons.people` has the wrong value. You could also have done `let wilsons = new Family([]);` and the smiths wouldn't have been affected. – Bergi Jan 20 '20 at 18:48
-
-