JavaScript “new Array(n)” and “Array.prototype.map” weirdness

JavaScript “new Array(n)” and “Array.prototype.map” weirdness

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:
>>> x = new Array(3)
[undefined, undefined, undefined]
>>> y = [undefined, undefined, undefined]
[undefined, undefined, undefined]

>>> x.constructor == y.constructor
true

>>> x.map(function(){ return 0; })
[undefined, undefined, undefined]
>>> y.map(function(){ return 0; })
[0, 0, 0]

What’s going on here? Is this a bug, or am I misunderstanding how to use new Array(3)?

Solutions/Answers:

Solution 1:

It appears that the first example

x = new Array(3);

Creates an array with undefined pointers.

And the second creates an array with pointers to 3 undefined objects, in this case the pointers them self are NOT undefined, only the objects they point to.

y = [undefined, undefined, undefined]
// The following is not equivalent to the above, it's the same as new Array(3)
y = [,,,];

As map is run in the context of the objects in the array I believe the first map fails to run the function at all while the second manages to run.

Related:  JavaScript: getting ImageData without canvas

Solution 2:

I had a task that I only knew the length of the array and needed to transform the items.
I wanted to do something like this:

let arr = new Array(10).map((val,idx) => idx);

To quickly create an array like this:

[0,1,2,3,4,5,6,7,8,9]

But it didn’t worked because:
see Jonathan Lonowski’s answer a few answers upper.

Solution could be to fill up the array items with any value (even with undefined) using Array.prototype.fill()

let arr = new Array(10).fill(undefined).map((val,idx) => idx);
console.log(new Array(10).fill(undefined).map((val, idx) => idx));

Update

Another solution could be:

let arr = Array.apply(null, Array(10)).map((val, idx) => idx);
console.log(Array.apply(null, Array(10)).map((val, idx) => idx));

Solution 3:

With ES6, you can do [...Array(10)].map((a, b) => a) , quick and easy!

Solution 4:

ES6 solution:

[...Array(10)]

Doesn’t work on typescript (2.3), though

Solution 5:

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.

Solution 6:

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.

Related:  How to call a REST web service API from JavaScript?

I believe this is the same for all iteration methods.