Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is Array.apply actually doing

After reading this SO Question, I'm still a little confused as to what Array.apply is actually doing. Consider the following snippet:

new Array(5).map(function(){   return new Array(5); }); 

I expect this to init an array with 5 undefined entries, then map over them creating a two dimensional array of 5x5);

Instead I just get the array as if it was never mapped over:

[undefined, undefined, undefined, undefined, undefined] 

When I wrap the constructor call to array in an Array.apply call, then map over that, it works as expected:

Array.apply(null, new Array(5)).map(function(){   return new Array(5); }); 

resulting in;

[[undefined, undefined, undefined, undefined, undefined],  [undefined, undefined, undefined, undefined, undefined],  [undefined, undefined, undefined, undefined, undefined],  [undefined, undefined, undefined, undefined, undefined],  [undefined, undefined, undefined, undefined, undefined]]; 

What's the deal? Is Array.apply just another way of calling new Array(), or Array.prototype.constructor? Are there any other situations where this would be advantageous? Also, why didn't my first approach pick up on the map I was sending it through?

Thanks! -Neil

like image 707
Neil Avatar asked Aug 26 '14 18:08

Neil


People also ask

What is array apply?

Description. This method applies the supplied function to every item in the target array, one by one, storing each result in place of the value that was used to generate it. Contrast apply() with map() which doesn't change the target array's items but instead saves the results in a new array.

What does apply () do in JavaScript?

The apply() method allows an object to borrow the method of another object without duplicating the code. The server object doesn't have the turnOn() and turnOff() methods. In this example, the server object borrows the turnOn() method of the computer object.

What is array push apply?

Using apply to append an array to another Because push() accepts a variable number of arguments, you can also push multiple elements at once. But if you pass an array to push() , it will actually add that array as a single element, instead of adding the elements individually, ending up with an array inside an array.

What is the difference between Call & apply?

The Difference Between call() and apply() The difference is: The call() method takes arguments separately. The apply() method takes arguments as an array. The apply() method is very handy if you want to use an array instead of an argument list.


1 Answers

Good question!

The Array constructor function (with can be used without new), when passed more than 1 argument, creates an array containing the arguments passed in as its elements. So you can do this:

Array(1, 2, 3); // => [1, 2, 3] 

As you probably know, Function.prototype.apply allows you to provide arguments to a function in the form of an array. So calling Array.apply (which just inherits its .apply() method from Function's prototype; any function that is an instance of Function would allows you to do this), which will be functionality equivalent to the code above:

Array.apply(null, [1, 2, 3]); // => [1, 2, 3] 

Now, here's why things are a bit confusing. The Array.prototype.map method is spec'd in such a way that it deals with sparse arrays specially. A sparse array is one that has a "length" that is greater than the number of elements that have actually been inserted. For example:

var arr = []; arr[0] = 'foo'; arr[5] = 'bar'; 

The array constructed above will have a length property of 6, because it has an element at index 0 and one at index 5. However, since no elements were ever inserted between those indices, if you call map on it you'll see that the mapping function does not get applied to the missing elements:

// This should throw, right? Since elements 1 through 4 are undefined? var lengths = arr.map(function(s) { return s.length; });  // Nope! lengths; // => [3, , , , , 3] 

And why are we seeing this behavior in your example with new Array(5)? You guessed it: because the array constructor, when given a single argument, creates a sparse array with the specified length.

So the issue here is that while map (and other methods on Array.prototype, such as forEach) behaves specially with respect to sparse arrays by skipping over the missing values, the Function.prototype.apply method does not have any such special behavior.

like image 178
Dan Tao Avatar answered Oct 12 '22 22:10

Dan Tao