I\'ve observed this in Firefox-3.5.7/Firebug-1.5.3 and Firefox-3.6.16/Firebug-1.6.2
When I fire up Firebug:
From the MDC page for map:
[...]
callback
is invoked only for indexes of the array which have assigned value; [...]
[undefined]
actually applies the setter on the index(es) so that map
will iterate, whereas new Array(1)
just initializes the index(es) with a default value of undefined
so map
skips it.
I believe this is the same for all iteration methods.
Since the question is why, this has to do with how JS was designed.
There are 2 main reasons I can think of to explain this behavior:
Performance: Given x = 10000
and new Array(x)
it is wise for the constructor to avoid looping from 0 to 10000 to fill the array with undefined
values.
Implicitly "undefined": Give a = [undefined, undefined]
and b = new Array(2)
, a[1]
and b[1]
will both return undefined
, but a[8]
and b[8]
will also return undefined
even if they're out of range.
Ultimately, the notation empty x 3
is a shortcut to avoid setting and displaying a long list of undefined
values that are undefined
anyway because they are not declared explicitly.
Note: Given array a = [0]
and a[9] = 9
, console.log(a)
will return (10) [0, empty x 8, 9]
, filling the gap automatically by returning the difference between the two values declared explicitly.
For reasons thoroughly explained in other answers, Array(n).map
doesn't work. However, in ES2015 Array.from accepts a map function:
let array1 = Array.from(Array(5), (_, i) => i + 1)
console.log('array1', JSON.stringify(array1)) // 1,2,3,4,5
let array2 = Array.from({length: 5}, (_, i) => (i + 1) * 2)
console.log('array2', JSON.stringify(array2)) // 2,4,6,8,10
I think the best way to explain this is to look at the way that Chrome handles it.
>>> x = new Array(3)
[]
>>> x.length
3
So what is actually happening is that new Array() is returning an empty array that has a length of 3, but no values. Therefore, when you run x.map
on a technically empty array, there is nothing to be set.
Firefox just 'fills in' those empty slots with undefined
even though it has no values.
I don't think this is explicitly a bug, just a poor way of representing what is going on. I suppose Chrome's is "more correct" because it shows that there isn't actually anything in the array.
The arrays are different. The difference is that new Array(3)
creates an array with a length of three but no properties, while [undefined, undefined, undefined]
creates an array with a length of three and three properties called "0", "1" and "2", each with a value of undefined
. You can see the difference using the in
operator:
"0" in new Array(3); // false
"0" in [undefined, undefined, undefined]; // true
This stems from the slightly confusing fact that if you try to get the value of a non-existent property of any native object in JavaScript, it returns undefined
(rather than throwing an error, as happens when you try to refer to a non-existent variable), which is the same as what you get if the property has previously been explictly set to undefined
.
If you are doing this in order to easily fill up an array with values, can't use fill for browser support reasons and really don't want to do a for-loop, you can also do x = new Array(3).join(".").split(".").map(...
which will give you an array of empty strings.
Quite ugly I have to say, but at least the problem and intention are quite clearly communicated.