maffe
maffe

Reputation: 220

Javascript deep copy (values) not working in array

Hi I'm playing around with node.js and Javascript for an upcoming project. I have an array of template objects called templateValues.

Now I'd like to copy these two objects with altered id's into an new array myArray.

let templateValues = [{'id':1 , 'type': 'a'},{'id':2 , 'type': 'b'}];
let myArray = [];

for (let index = 0; index < 10; index++) {
 myArray =  myArray.concat(templateValues.map(e => {
   e.id = Math.random(); // suppose this gives a unique id
   return e;
  }).slice(0));	
}
console.log(myArray);

OUTPUT:

{id: 0.13413583461207668, type: "a"}
{id: 0.7426427992455211, type: "b"}
{id: 0.13413583461207668, type: "a"}
{id: 0.7426427992455211, type: "b"}
{id: 0.13413583461207668, type: "a"}
{id: 0.7426427992455211, type: "b"}
{id: 0.13413583461207668, type: "a"}
{id: 0.7426427992455211, type: "b"}
...

Why are the ids all the same even if I do slice(0) of the altered templateValues-array to get a "data-copy"?!

Upvotes: 1

Views: 92

Answers (2)

intentionally-left-nil
intentionally-left-nil

Reputation: 8284

When you call slice, you are modifying the array object, not the contents of the array itself. There are no lines of code in your example that clone the underlying object, and thus, when you set e.id = Math.random(), you are editing the same object over and over again.

The fix here is to clone e before you modify it. Try Object.assign({}, e) before editing it to make a shallow copy of each item.

See the below example:

let templateValues = [{'id':1 , 'type': 'a'},{'id':2 , 'type': 'b'}];
let myArray = [];

for (let index = 0; index < 10; index++) {
    myArray =  myArray.concat(templateValues.map(e => {
       const eCopy = Object.assign({}, e, {id: Math.random()})
       return eCopy;
  }).slice(0)); 
}
console.log(myArray);

You can also use the ES2018 object spread syntax to achieve the same result. Simply replace Object.assign with {...e, id: Math.random()}

Upvotes: 4

baao
baao

Reputation: 73241

The other answer and comment already explains the problem, so I'll just offer a solution - you can use below to get what you need, the length of the new array can be set to whatever you want, the types will repeat itself in the same order of your original array

let templateValues = [{'id':1 , 'type': 'a'},{'id':2 , 'type': 'b'}];
const newArr = Array.from ({length: 10}, (_, i) => ({
    id: Math.random(),
    type: templateValues[i % templateValues.length].type
}));
console.log(newArr);

Upvotes: 1

Related Questions