Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array.apply(null, Array(9)) vs new Array(9) [duplicate]

Tags:

javascript

What exactly is the difference between:

Array(3)
// and
Array.apply(null, Array(3) )

The first returns [undefined x 3] while the second returns [undefined, undefined, undefined]. The second is chainable through Array.prototype.functions such as .map, but the first isn't. Why?

like image 302
cat-t Avatar asked Feb 09 '15 18:02

cat-t


3 Answers

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.

like image 113
adeneo Avatar answered Sep 23 '22 23:09

adeneo


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.

like image 35
Pointy Avatar answered Sep 25 '22 23:09

Pointy


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);
like image 35
RobG Avatar answered Sep 25 '22 23:09

RobG