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

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?


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);

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.