最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Why presize a JavaScript Array? - Stack Overflow

programmeradmin4浏览0评论

Firebug represents (new Array(N)) as an array with N undefineds in it. I recently ran across a scenario that demonstrated that a sized array with all undefined values in it is different from a newly constructed, sized array. I'd like to understand the difference.

Suppose you want to generate a list of random integers between 0 and 1000.

function kilorange() {
    return Math.floor(Math.random() * (1001));
}

no_random_numbers = (new Array(6)).map(kilorange);
my_random_numbers = [undefined, undefined, undefined,
                     undefined, undefined, undefined].map(kilorange);

I would have expected no_random_numbers and my_random_numbers to be equivalent, but they're not. no_random_numbers is another array of undefineds, whereas my_random_numbers is an array with six random integers in it. Furthermore, after throwing a console.count statement into kilorange, I learned that my function never gets called for the array created with the Array constructor.

What is the difference, and why does map (and presumably other iterable methods) not treat the above arrays the same?

Firebug represents (new Array(N)) as an array with N undefineds in it. I recently ran across a scenario that demonstrated that a sized array with all undefined values in it is different from a newly constructed, sized array. I'd like to understand the difference.

Suppose you want to generate a list of random integers between 0 and 1000.

function kilorange() {
    return Math.floor(Math.random() * (1001));
}

no_random_numbers = (new Array(6)).map(kilorange);
my_random_numbers = [undefined, undefined, undefined,
                     undefined, undefined, undefined].map(kilorange);

I would have expected no_random_numbers and my_random_numbers to be equivalent, but they're not. no_random_numbers is another array of undefineds, whereas my_random_numbers is an array with six random integers in it. Furthermore, after throwing a console.count statement into kilorange, I learned that my function never gets called for the array created with the Array constructor.

What is the difference, and why does map (and presumably other iterable methods) not treat the above arrays the same?

Share Improve this question asked Oct 16, 2011 at 7:11 kojirokojiro 77.1k19 gold badges150 silver badges212 bronze badges 5
  • 1 @FelixKling Just a bit ahead of you, thanks to davin's comment below. But this brings out the title question. What good is it to create an empty array with a nonzero length? – kojiro Commented Oct 16, 2011 at 7:38
  • 2 The only example I've ever seen using it is new Array(6).join("some text") which will repeat "some text" 6 times. – Tetaxa Commented Oct 16, 2011 at 7:50
  • It is not of any good, that's why no one is doing this. But it's in the specification, and you cannot just drop it without breaking some scripts. What could be an advantage is that the length of the array does not have to be increased every time set a new element, though the performance gain is probably negligible. – Felix Kling Commented Oct 16, 2011 at 8:13
  • Wait, what the heck? @Tetaxa, why does that work? – kojiro Commented Oct 17, 2011 at 16:38
  • @kojiro I'm not sure, but I guess it's in the javascript specs, there are test cases for it here code.google.com/p/v8/source/browse/branches/bleeding_edge/test/… – Tetaxa Commented Oct 17, 2011 at 17:51
Add a comment  | 

6 Answers 6

Reset to default 7

The ES standard (15.4.4.19) defines the algorithm for map, and it's quite clear from step 8b that since your array doesn't actually have any of those elements, it will return an "empty" array with length 6.

As others have mentioned, it has to do with array objects in js being (unlike their rigid C counterparts) very dynamic, and potentially sparse (see 15.4 for the sparsity test algorithm).

When you use:

var a = new Array(N);

no values are stored in the new array and even the index "properties" are not created. That is why map won't do a thing on that array.

The fact that Firebug does that is a bug/feature of the Firebug. You should remember that it's console is an eval envelope. There are other bug/features in the Firebug console.

For example in Chrome console you'll see the above a array as [].

Look at this sample and run it: http://jsfiddle.net/ArtPD/1/ (it create the two arrays without using the map over them and then list the key/values of each one of them)

I would say that (new Array(6)) doesn't allocate "named" properties (so it doesn't create "1": undefined, "2": undefined...) while the other form [undefined, ... ] does.

In fact if I use a for (var i in ... ) the two outputs are:

no_random_numbers


my_random_numbers
0 undefined
1 undefined
2 undefined
3 undefined
4 undefined
5 undefined

Good question, good answers. I fiddled a bit with the map prototype from MDN. If it's adapted like this, map would work for a new Array([length])

Array.prototype.map = function(callback, thisArg) {
    var T, A, k;
    if (this == null) {
      throw new TypeError(" this is null or not defined");
    }
    var O = Object(this);
    var len = O.length >>> 0;
    if ({}.toString.call(callback) != "[object Function]") {
      throw new TypeError(callback + " is not a function");
    }
    if (thisArg) {
      T = thisArg;
    }
    A = new Array(len);
    k = 0;
    while(k < len) {
      var kValue, mappedValue;
      if (k in O || (O.length && !O[k])) {
//                  ^ added this
        kValue = O[ k ];
        mappedValue = callback.call(T, kValue, k, O);
        A[ k ] = mappedValue;
      }
      k++;
    }
    return A;
};

Based on Casy Hopes answer you could also make a mapx-extension to be able to use map with some new Array([length]):

Array.prototype.mapx = function(callback){
  return this.join(',').split(',').map(callback);
}
//usage
var no_random_numbers = new Array(6).mapx(kilorange);

To answer the title question (why presize arrays), the only use that I've come across for initializing an Array(n) array is to create an n-1 length string:

var x = Array(6).join('-'); // "-----"

To answer why you would presize an array, you'd do it so you don't have to do as many individual allocations. Allocating memory takes some time, and it might trigger a garbage collection run that can take a lot longer.

On a typical web page, you won't notice a difference, but if you're doing something major, it might help a fair bit.

发布评论

评论列表(0)

  1. 暂无评论