This question already has answers here:
Closed last month.
I was trying out a question on Hackerrank where I needed to create an array of array (basically 2d arrays).
My go-to one liner would be const counter = new Array(4).fill([])
However, I realized that it would create a 2D array but applying any function to the array would cause it to apply to all the elements.
let count = new Array(4).fill([])
count[0].push("Test")
console.log(JSON.stringify(count))
The outcome would be all the sub-arrays having the same value of "Test" inside them.
The final solution would be:
let count = Array.from(Array(4), () => new Array());
count[0].push("Test")
console.log(JSON.stringify(count))
May I ask the reason why it's not working as expected?
Because .fill()
takes the argument and, if it's an object, it copies the reference to that object into every index of the new array. Since in fact []
is an object, your new array ends up being filled with references to the same array.
From the docs:
If the first parameter is an object, it will copy its reference and fill the array with references to that object.
.fill([]) | New Array
+----------+------+------+------+------+
| | | | | |
Memory | [] |indx0 |indx1 |indx2 |indx3 |
| | | | | |
+----------+------+------+------+------+
^ | | | |
| | | | |
+--------+ | | |
+---------------+ | |
+----------------------+ |
+-----------------------------+
The four indexes are pointing to the same value in memory, so when you're pushing an element, you're doing on the same value (array) in memory.
When you use Array(4).fill([])
, you are actually filling count with only one array ([]
). All the elements inside count
refer to the same array. This is why when you alter the first element (which is also referenced by the second, third, and fourth element) and print count
, count
's elements all have the same array object. The same referencing scenario in fill happens to all objects, not just arrays.
Here, you can see that the second, third, and fourth element refers (denoted by /**ref:2**/
) to the object with the same id
(/**id:2**/
) as the first element:
let count = new Array(4).fill([])
count[0].push("Test")
console.log(count)
Let me explain:
let count = new Array(4).fill([])
Here you create just 2 arrays actually. one is []
and second contains 4 links to []
.
In other words you are creating an array of 4 links to the single instance of array.
--
let count = Array.from(Array(4), () => new Array());
Here you create 5 different arrays. 4 different empty []
and array that contains 4 links, one link to each unique []
.
In other words here you create array filled with a different arrays