Array.prototype.fill() with object passes reference and not new instance

JavascriptArrays

Javascript Problem Overview


I was toying a bit and was trying to instantiate a new array of length x, where all elements of that array were initialized to a value y:

var arr = new Array(x).fill(y);

This works well if the value of y is anything other than an object. Meaning that if y is an object, the following is true:

var arr = new Array(2).fill({});
arr[0] === arr[1]; //is true;
arr[0].test = 'string';
arr[1].test === 'string'; //is also true;

Is there any way to state that a new object should be created for each element while using the fill-function? Or should I just convert it to a loop?

Javascript Solutions


Solution 1 - Javascript

You can first fill the array with any value (e.g. undefined), and then you will be able to use map:

var arr = new Array(2).fill().map(u => ({}));

var arr = new Array(2).fill().map(Object);

Solution 2 - Javascript

The accepted answer is good and would work in 90% of cases.

But if you are making high-performance JS application, and if you work with big/huge arrays, Array.map(..) creates big overload in both - memory and processor use, as it creates a copy of an array.

I recommend to use the classic for loop:

    a = new Array(ARRAY_SIZE);
    for (var i = 0; i < ARRAY_SIZE; i++) {
        a[i] = [];
    }
    // or it's one line alternative
    for (var i = 0, a = []; i < ARRAY_SIZE; a[i++] = []);

I tested six alternatives and got this:

  • Array.map(), as proposed above (11x times!!! slower):

     a = new Array(ARRAY_SIZE).fill().map(u => { return []; });
    
  • for loop, the best one (fastest):

     // Standard multi-line way
     a = new Array(ARRAY_SIZE);
     for (var i = 0; i < ARRAY_SIZE; i++) {
         a[i] = [];
     }
    
     // One line syntax
     for (var i = 0, a = []; i < ARRAY_SIZE; a[i++] = []);
    
  • forEach (6x time slower):

     a = new Array(ARRAY_SIZE).fill();
     a.forEach((val, i) => {
         a[i] = [];
     })
    

[UPDATE 2020-08-27] One more way proposed by Ilias Karim below

  • Array.from (30x times!!! slower) - apparently worse in terms of performance, despite the nicest syntax :(

     a = Array.from({ length: ARRAY_SIZE }, () => []);
    
  • [..Array(..)] (5x times!!! slower)

     a = [...Array(ARRAY_SIZE)].map(_=>([]))
    
  • Array.push(..), second place in terms of performance (2x times!!! slower)

     let a = [], total = ARRAY_SIZE;
     while(total--) a.push([]);
    

PS. I used this fiddle for tests.

Solution 3 - Javascript

One performant solution: Array.from({ length: 5 }, () => new Object())

Solution 4 - Javascript

Shortest Possable:

let node =  [...Array(2)].map(_=>({}))
console.log(node)

Solution 5 - Javascript

Ilias Karim's answer is most excellent. I just did the following:

a = Array.from({length:l}, () => new Array(c).fill(prefix));

to create a pre-filled 2D array of the specified size, l by c, filled with prefix. Now my code can fill in the slots in the 2D matrix that need non-prefix values.

Solution 6 - Javascript

You could also solve this by the following workaround.

var arr = new Array(2).fill({});
arr = JSON.parse(JSON.stringify(arr));

Solution 7 - Javascript

I wrote a blog post about this: http://www.samhenderson.xyz/posts/12

But the TLDR is that if you want to avoid chaining multiple function e.g. fill, map. And want to avoid writing a loop, then you can use:

const array = Array.from({ length: 2 },()=>({}))

For an array of arrays:

const array = Array.from({ length: 2 },()=>([]))

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKoen MorrenView Question on Stackoverflow
Solution 1 - JavascriptOriolView Answer on Stackoverflow
Solution 2 - JavascriptKostanosView Answer on Stackoverflow
Solution 3 - JavascriptIlias KarimView Answer on Stackoverflow
Solution 4 - JavascriptRickView Answer on Stackoverflow
Solution 5 - JavascriptjamessView Answer on Stackoverflow
Solution 6 - JavascriptArun DView Answer on Stackoverflow
Solution 7 - JavascriptSam HendersonView Answer on Stackoverflow