0

I was working on a fun little thing on JS using nested arrays and was frustrated for nearly half an hour by this weird behavior. Here's some example code that gives the behavior:

var myArray = new Array(2);
myArray.fill([]);
out1.innerHTML = myArray;
myArray[0].push(0);
out2.innerHTML = myArray;
<div id="out1"></div>
<div id="out2"></div>

It's a bit tricky to see it how it's printed, but the push() is acting on every single nested array and not just myArray[0]. At first I thought it was something with push(), but I did some fiddling and found out that if I replaced myArray.fill([]); with for(var i = 0; i < myArray.length; i++) { myArray[i] = []; } that push() would then work fine, as in this example:

var myArray = new Array(2);
for(var i = 0; i < myArray.length; i++) { myArray[i] = []; }
out1.innerHTML = myArray;
myArray[0].push(0);
out2.innerHTML = myArray;
<div id="out1"></div>
<div id="out2"></div>

A few more details: it doesn't matter how big the parent array is, every nested array is pushed. It doesn't matter which nested array push() is called for, they'll all still be pushed. It doesn't matter what value is pushed into each nested array, it'll be pushed into them all.
Also, if I made a function to do the exact same thing as the for loop, the bug still happened. See snippet:

var myArray = new Array(2);
function fill(arr, filler) {
  for(var i = 0; i < arr.length; i++) { arr[i] = filler; }
  return arr;
}
myArray = fill(myArray, []);
out1.innerHTML = myArray;
myArray[0].push(0);
out2.innerHTML = myArray;
<div id="out1"></div>
<div id="out2"></div>

I haven't fiddled around to find out if it does this with more than one layer of nested arrays (so for example I don't know if it would do this to something like [ [ [], [] ], [ [], [] ] ] ).
As I said, I have a workaround for this using the for loop to fill the array instead of using myArray.fill(), but I'm wondering if anyone can explain the cause of this weird bug.

Matt Pasta
  • 183
  • 7
  • 1
    `myArray.fill([])` fills each element of the array with a reference to the same array (the []) - this is not a bug as you claim, it is working as intended - you could do `var myArray = Array.from({length:2}, ()=>[])` to substitute the first two lines in your first code snippet – Jaromanda X Sep 02 '20 at 09:18

1 Answers1

2

Array.fill([]) will create only one subarray, which is then assigned to every entry of the myArray array. Any mutation to that single subarray will be seen in all array slots, whether you look at myArray[0] or myArray[1], as both reference the same, single subarray.

What you really want, is to create a separate subarray per slot in myArray. You could for instance define the array in one go, using Array.from, but there are of course many ways to accomplish this:

let myArray = Array.from({length: 2}, () => []) 
trincot
  • 317,000
  • 35
  • 244
  • 286