array.push(element) vs array[array.length] = element

13,025

The fastest way to do it with current JavaScript technology, while also using minimal code, is to store the last element first, thereby allocating the full set of array indices, and then counting backwards to 0 while storing the elements, thereby taking advantage of nearby memory storage positions and minimizing cache misses.

var arr3 = [];
for (var i = len; i>0;){
    i--;
    arr2[i] = numbers[i] * 2;
}
alert(arr2);

Note that if the number of elements being stored is "big enough" in the view of the JavaScript engine, then the array will be created as a "sparse" array and never converted to a regular flat array.

Yes, I can back this up. The only problem is that JavaScript optimizers are extremely aggressive in throwing away calculations that aren't used. So in order for the results to be calculated fairly, all the results have to be stored (temporarily). One further optimization that I believed to be obsolete, but actually improves the speed even further is to pre-initialize the array using new Array(*length*). That's an old-hat trick that for a while made no difference, but no in the days of extreme JavaScript engine optimizations, it appears to make a difference again.

<script>
function arrayFwd(set) {
var x = [];
for (var i = 0; i<set.length; i++)
x[x.length] = set[i];
return x;
}

function arrayRev(set) {
var x = new Array(set.length);
for (var i = set.length; i>0;) {
i--;
x[i] = set[i];
}
return x;
}

function arrayPush(set) {
var x = [];
for (var i = 0; i<set.length; i++)
x.push(set[i]);
return x;
}

results = []; /* we'll store the results so that
optimizers don't realize the results are not used
and thus skip the function's work completely */
function timer(f, n) {
return function(x) {
var n1 = new Date(), i = n;
do { results.push(f(x)); } while (i-- > 0); // do something here
return (new Date() - n1)/n;
};
}

set = [];
for (i=0; i<4096; i++)
set[i] = (i)*(i+1)/2;

timers = {
forward: timer(arrayFwd, 500),
backward: timer(arrayRev, 500),
push: timer(arrayPush, 500)
};
for (k in timers) {
document.write(k, ' = ', timers[k](set), ' ms<br />');
}
</script>

Opera 12.15:

forward = 0.12 ms backward = 0.04 ms push = 0.09 ms

Chrome (latest, v27):

forward = 0.07 ms backward = 0.022 ms push = 0.064 ms

(for comparison, when results are not stored, Chrome produces these numbers: forward = 0.032 ms backward = 0.008 ms push = 0.022 ms

This is almost four times faster versus doing the array forwards, and almost three times faster versus doing push.)

IE 10: forward = 0.028 ms backward = 0.012 ms push = 0.038 ms

Strangely, Firefox still shows push as faster. There must be some code re-writing going on under the hood with Firefox when push is used, because accessing a property and invoking a function are both slower than using an array index in terms of pure, un-enhanced JavaScript performance.

Share:
13,025

Related videos on Youtube

Tom
Author by

Tom

Updated on May 25, 2022

Comments

  • Tom
    Tom almost 2 years

    I was wondering if there is a reason to choose

    array.push(element)
    

    over

    array[array.length] = element
    

    or vice-versa.

    Here's a simple example where I have an array of numbers and I want to make a new array of those numbers multiplied by 2:

    var numbers = [5, 7, 20, 3, 13];
    
    var arr1 = [];
    var len = numbers.length;
    for(var i = 0; i < len; i++){
        arr1.push(numbers[i] * 2);
    }
    alert(arr1);
    
    var arr2 = [];
    for(var i = 0; i < len; i++){
        arr2[arr2.length] = numbers[i] * 2;
    }
    alert(arr2);
    
    • Ian
      Ian almost 11 years
      They both provide reasons why to use either method
    • kennebec
      kennebec almost 11 years
      There is no reason to calculate the array length each time-you can use i, or if the array does not increment for each i, increment another variaible.
    • Manohar Reddy Poreddy
      Manohar Reddy Poreddy about 4 years
      Lot of confusion here. Check this out: jsperf.com/array-direct-assignment-vs-push
  • Tom
    Tom almost 11 years
    Can you back this up?
  • Qantas 94 Heavy
    Qantas 94 Heavy almost 11 years
    In fact, it will create a sparse array first, change the length of the array and then fill up each of the elements in reverse order, and then only when the 0 index is filled, then it is converted to a "regular" array. In my testing, when allocating an array, this method is in fact slower than a forward loop. Also, your code isn't completely optimised.
  • Ian
    Ian almost 11 years
    @user2246674 There's really no consistency across browsers, so it's not really worth it to try. Differences occur between sizes of the array, browser, and the way [] is used. Some people use [i] in a loop, some use [array.length], which have different implications
  • leopic
    leopic almost 11 years
    +1 on asking for a back up on "the fastest way to do it"
  • Joseph Myers
    Joseph Myers almost 11 years
    @Qantas94Heavy You are right that this works differently today than it did the last time I tested it. Before, doing it backwards was always a big winner. Now it seems that browsers still create a sparse array as you say, in particular Firefox, which performs more quickly with push. In principle, doing it backwards should be the fastest, because it does the same thing as initializing the full array and then storing adjacent elements. But due to JavaScript engine optimizations, what is written in code is not what actually happens in the background.
  • Ben Gubler
    Ben Gubler about 5 years
    In a lot of my benchmarks, looping through an array forwards often ends up faster than i--, probably because of engine optimizations that expect you to do it that way