Difference between Array.apply(null, Array(x) ) and Array(x)
There is a difference, a quite significant one.
The Array
constructor either accepts one single number, giving the lenght of the array, and an array with "empty" indices is created, or more correctly the length is set but the array doesn't really contain anything
Array(3); // creates [], with a length of 3
When calling the array constructor with a number as the only argument, you create an array that is empty, and that can't be iterated with the usual Array methods.
Or... the Array constructor accepts several arguments, whereas an array is created where each argument is a value in the array
Array(1,2,3); // creates an array [1,2,3] etc.
When you call this
Array.apply(null, Array(3) )
It get's a little more interesting.
apply
accepts the this
value as the first argument, and as it's not useful here, it's set to null
The interesting part is the second argument, where an empty array is being passed in.
As apply
accepts an array it would be like calling
Array(undefined, undefined, undefined);
and that creates an array with three indices that's not empty, but have the value actually set to undefined
, which is why it can be iterated over.
TL;DR
The main difference is that Array(3)
creates an array with three indices that are empty. In fact, they don't really exist, the array just have a length of 3
.
Passing in such an array with empty indices to the Array constructor using apply
is the same as doing Array(undefined, undefined, undefined);
, which creates an array with three undefined
indices, and undefined
is in fact a value, so it's not empty like in the first example.
Array methods like map()
can only iterate over actual values, not empty indices.
The .map()
API does not iterate over completely uninitialized array elements. When you make a new array with the new Array(n)
constructor, you get an array with the .length
you asked for but with non-existent elements that will be skipped by methods like .map()
.
The expression Array.apply(null, Array(9))
explicitly populates the newly-created array instance with undefined
, but that's good enough. The trick is whether or not the in
operator will report that the array contains an element at the given index. That is:
var a = new Array(9);
alert(2 in a); // alerts "false"
That's because there really is no element at position 2
in the array. But:
var a = Array.apply(null, Array(9));
alert(2 in a); // alerts "true"
The outer call to the Array constructor will have explicitly populated the elements.
This is an artifact of how apply works. When you do:
new Array(9)
an empty array is created with a length of 9. map does not visit non–existent members, so does nothing at all. However, apply turns the array into a list using CreateListFromArrayLike so it turns the formerly empty array into a parameter list like:
[undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined];
that is passed to Array to create an array with 9 members, all with a value of undefined. So now map will visit them all.
BTW, ECMAScript 2015 has Array.prototype.fill for this (also see MDN) so you can do:
Array(9).fill(0);