Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
160 views
in Technique[技术] by (71.8m points)

javascript - 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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...