4

In Python, I can do: l = [{'d': 3}] * 5 to get [{'d': 3}, {'d': 3}, {'d': 3}, {'d': 3}, {'d': 3}].

What is the equivalent way of doing this in ES6, that actually clones the objects and not just copying the reference?

edit: Basically, is there a shortcut in ES6 to make the following array:

const arr = [
   {"d": 3},
   {"d": 3},
   {"d": 3},
   {"d": 3},
   {"d": 3},
   {"d": 3},
   {"d": 3},
   {"d": 3},
   {"d": 3},
   {"d": 3},
   {"d": 3},
   {"d": 3},
];

?

hans-t
  • 3,093
  • 8
  • 33
  • 39
  • Your Python code just copies the reference, doesn't it? `l[0]['d'] = 2` affects the whole list. – Marius Apr 20 '16 at 04:45
  • yep, I know that, and I already indicated that I want to clone the object and not just copying the reference. – hans-t Apr 20 '16 at 04:46
  • What @Marius has said is perfect. Read [Python list of lists, changes reflected across sublists unexpectedly](http://stackoverflow.com/q/240178) – Bhargav Rao Apr 20 '16 at 04:46

5 Answers5

4

The literal equivalent would be

const arr = Array(5).fill({d: 3}); 

this will fill the array with the same object reference, five times.

To get clones is slightly more involved. Consider:

Array.apply(null, Array(5)).map(_ => ({d: 3}));

or

Array(5).fill(0).map(_ => ({d: 3}));

Here's a quick and dirty performance comparison. For small sizes of n, the O(n) fill seems to out perform what is really the creation of two arrays. As n grows, this seems to flip around.

Definitely play with the numbers, and construct your own tests if this is an important factor.

JSFiddle

'use strict';

const loops = 100000;
const size = 50;

const a0 = performance.now();
for (let i = 0; i < loops; i++)
 Array.apply(null, Array(size)).map(_ => ({d: 3}));
const a1 = performance.now();
console.log('Apply %fms', a1 - a0);


const f0 = performance.now();
for (let i = 0; i < loops; i++)
 Array(size).fill(0).map(_ => ({d: 3}));
const f1 = performance.now();
console.log('Fill %fms', f1 - f0);

Also, note that the apply method has the benefit of being valid ES5 when replacing the arrow function with a normal function.

Oka
  • 23,367
  • 6
  • 42
  • 53
2

I suppose you could do this:

new Array(6).fill(0).map(() => ({d: 3}));

(where 6 is the number you want.)

It's not quite as succinct, though.

Todd Christensen
  • 1,297
  • 8
  • 11
1

This solution seems like a good option:

var n = 10;
var items = Array.from(Array(n), _ => ({d: 3}));

Using the map function will make sure to create clones of the object.
Check more about the Array.from().

Dmitri Pavlutin
  • 18,122
  • 8
  • 37
  • 41
0

I'm not aware of an equivalent for duplicating an object in an array like you have there from python, but the easiest way to do clones of the properties of an object in JavaScript is to use the JSON.parse(JSON.stringify([myJsObj])), however if you are doing this in a loop it may cause negative performance.

let o = {d: 3}
let a = [];

for(let i = 0; i < 5; i++) {
    a.push(JSON.parse(JSON.stringify(o)));
}
weagle08
  • 1,763
  • 1
  • 18
  • 27
-1

l = new Array(3).fill({'d': 3})

mcbill
  • 367
  • 3
  • 12