(new Array(10)).map(function() { return 1;}) returns [, , , , , ...] ... Why? [duplicate]

I would expect the following code to return [1,1,1,1...]

(new Array(10)).map(function() { return 1;})

but it returns [, , , , , ...].

Moreover, (new Array(10)).length == 10 and (new Array(10))[0] == undefined are true.

And for z = function(){return 0;}; the expression z(undefined) === 0 is also true.

Yet I have noticed that [,,,,,,,,,,].map(function() { return 1; }) also returns [,,,,....].

Can anyone explain why?


Solution 1:

So. I would expect the following code to return [1,1,1,1...].

(new Array(10)).map(function() { return 1;}) But it returns [, , , , , ...].

Right, because new Array(10) creates an array with no elements with a length of 10, and map only iterates over elements that actually exist. (And yes, this is surprising. :-) )

Moreover, (new Array(10)).length == 10 and (new Array(10))[0] == undefined are true.

Again correct, because (again) new Array(10) doesn't put any elements in the array, so accessing [0] gives you undefined.

JavaScript's standard arrays aren't really arrays at all, and they can have a length that's a positive number without having any entries in them. They're a form of "sparse" array.

Let's take a simpler example:

var a = new Array(10);
a[2] = 1;

That array contains one element, the element at index 2. There is no element at index 0, no element at index 1, and no elements at indexes 3 and above. It just has gaps there. You can tell by asking it:

console.log(0 in a); // "false"
console.log(1 in a); // "false"
console.log(2 in a); // "true"

Standard arrays in JavaScript are just objects with special behavior assigned to length, special behavior assigned to a class of property names (loosely, numeric ones), and that are backed by Array.prototype.

This is all in contrast to the newer "typed" arrays, Int32Array and such, which are true arrays in the traditional sense.

Solution 2:

This will work:

Array.apply(null, Array(10)).map(…

Live demo: http://jsfiddle.net/xXG5p/

You have to make the array dense first. new Array(n) creates a sparse array. Sparse arrays do have a length but they have no elements. Hence, a .map() call will not iterate at all.

Using my code above, you will create a dense array that does contain elements (whose values are initially set to null).

Solution 3:

Here is what the Mozilla Developer Network says about Array.prototype.map:

callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.

When you call new Array(10), the Array you create believes it is 10-element long but none of its indexes have ever been assigned to. Here's an example of what happens if you use a literal array for which you have not set values for some indices:

[1, , 3].map(function () {return "a"})

The value you get is:

[ 'a', , 'a' ]

Because at index 1, no value was assigned.