6

In my function, I have defined two arrays, the first (array1), has a pre-initialized length. I added the second array (array2) just for testing because I thought the first was behaving strangely.

My code:

function test(n = 3) {
  array1 = new Array(n).fill(new Array(n));
  array2 = [
    [undefined, undefined, undefined],
    [undefined, undefined, undefined],
    [undefined, undefined, undefined]
  ];

  document.getElementById("output").innerHTML = JSON.stringify(array1) + " (array 1) <br/>" + JSON.stringify(array2) + " (array 2)<br/><br/><hr/>";


  for (i = 0; i < n; i++) {
    array1[i][0] = i;
    array2[i][0] = i;
  }

  document.getElementById("output").innerHTML += JSON.stringify(array1) + " (array 1) <br/>" + JSON.stringify(array2) + " (array 2)<br/><br/><hr/>";

}
<button onclick="test();">Press to test</button>

<br/><br/>
<div id="output"></div>

In the for loop, I try to change the first value of the second dimensions. It should output [[0, undefined, undefined], [1, undefined, undefined], [2, undefined, undefined]], like the second array does.

My questions are: why does this happen? And, how can I make a pre-initialized array with length n in both dimensions, that behaves like the second array?

mplungjan
  • 169,008
  • 28
  • 173
  • 236
Sacha
  • 819
  • 9
  • 27
  • Sharing an article, why not to use new Array(), hope this helps -> https://coderwall.com/p/h4xm0w/why-never-use-new-array-in-javascript – mindaJalaj Aug 20 '17 at 14:38

2 Answers2

9

That's because in case of array1 it contains three arrays, but all three of them point to the same reference variable, that was evaluated when new Array(n) was executed:

var array1 = new Array(n).fill(new Array(n));

So when the for loop runs over array1 it is setting the value of the same array reference, while in case of array2 those three arrays are different reference variables.

Here's a slightly modified version of your snippet. Notice the entries into console when the value of array1's element is being changed. In case of array1 all three child arrays are changing, while in case of array2 the array referenced under the loop using index i is the only one that changes.

function test(n = 3) {
  array1 = new Array(n).fill(new Array(n));
  array2 = [
    [undefined, undefined, undefined],
    [undefined, undefined, undefined],
    [undefined, undefined, undefined]
  ];

  document.getElementById("output").innerHTML = JSON.stringify(array1) + " (array 1) <br/>" + JSON.stringify(array2) + " (array 2)<br/><br/><i>The commas with nothing in between mean undefined.</i><hr/>";


  for (i = 0; i < n; i++) {
    array1[i][0] = i;
    array2[i][0] = i;
    console.log("Array 1: " + JSON.stringify(array1));
    console.log("Array 2: " + JSON.stringify(array2));
  }

  document.getElementById("output").innerHTML += JSON.stringify(array1) + " (array 1) <br/>" + JSON.stringify(array2) + " (array 2)<br/><br/><i>The commas with nothing in between mean undefined.</i><hr/>";

}
<button onclick="test();">Press to test</button>

<br/><br/>
<div id="output"></div>
Nisarg Shah
  • 14,151
  • 6
  • 34
  • 55
  • Nice answer! However, how can I define `array1` so it is pre-initialized? The second array works for this case of n = 3, but, what if, for example, n = 5? – Sacha Aug 20 '17 at 14:46
  • I'd probably do something like [this](https://stackoverflow.com/a/966239/5894241), but Nina Scholz has explained a different method in her answer as well. – Nisarg Shah Aug 20 '17 at 14:50
  • 1
    Creating an entire for-loop seems a bit too much code for such a simple task :) so I think I'll use Nina's answer. – Sacha Aug 20 '17 at 14:54
7

Because Array.fill

The fill() method fills all the elements of an array from a start index to an end index with a static value.

takes a static value and fills the array with it. Therefore you get in every element of array1 the same array of the filling.

function test(n = 3) {
    var array1 = new Array(n).fill(new Array(n)),
        array2 = [[undefined, undefined, undefined], [undefined, undefined, undefined], [undefined, undefined, undefined]],
        i;

    for (i = 0; i < n; i++) {
        array1[i][0] = i;
        array2[i][0] = i;
    }

    document.getElementById("output").innerHTML = array1 + " (array 1) <br/>" + array2 + " (array 2)<br/><br/><i>The commas with nothing in between mean undefined.</i>";
    console.log(array1);
    console.log(array2);
}
<button onclick="test();">Press to test</button><br/><br/>
<div id="output"></div>

To get an independent filled array, you could use Array.from and map a new array with mapped values.

var array = Array.from({ length: 3 }, _ => Array.from({ length: 3 }, _ => 4));

array[0][0] = 0;
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392