OK, the tragedy was like this.
Everyone knows how convenient the javascript Array fill()
is to let users initialize array data elegantly. Perfect invention.
// create an array of length 6 with all elements equal to 0.
let arr = Array(6).fill(0)
It is even extremely useful if for creating a range of integers for iteration or some other fancy operations.
// you must fill the array or there won't be keys
Object.keys(Array(6).fill(0)).map((i) => dosomething(i));
Recently I was fascinated by these kinds of functional programming styles and mistakenly assumed that is was similar to Python collections.defaultdict()
which lets you pass a primitive or an object as a factory so that it will automatically new an independent value for each entry in the array.
Unfortunately, it is not the case.
fill(0)
works perfectly fine since the argument is a primitive. However, if you pass something like an object {}
, Every entry in the array will actually contain(or point to?) the same object. Every element will be the same.
That is to say, if you try to modify one of the element object(like, assign or change some value of a key), every single element will be modified as well, which is very unlikely to be your original intention.
> arr = Array(6).fill({})
[ {}, {}, {}, {}, {}, {} ]
> arr[3]['someKey'] = "hello"
'hello'
> arr
[
{ someKey: 'hello' },
{ someKey: 'hello' },
{ someKey: 'hello' },
{ someKey: 'hello' },
{ someKey: 'hello' },
{ someKey: 'hello' }
]
Boom.
This problem is very similar a classical trap in Python when you try to initialize an array of array in this very intuitive but disastrous way:
>>> arr = [[0] * 3 ] * 3
>>> arr
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> arr[1][1] = 777
>>> arr
[[0, 777, 0], [0, 777, 0], [0, 777, 0]]
Here the first level [0] * 3
is fine, but the second multiply is actually multiplying the reference to the array [0] * 3
, therefore changing one element in one array will lead to changing all of the corresponding element in other arrays (because they are the same reference!)
OK, everyone can start to laugh!
Top comments (2)
That's why you should always use
map
for scenarios like this:Output:
Thanks for the tip! This is much more elegant.