What is the best way to do loops in JavaScript

2019-01-21 11:34发布

问题:

I have stumbled into several methods of looping in JavaScript, what I like the most is:

for(var i = 0; i < a.length; i++){
    var element = a[i];
}

But as tested here (http://www.robertnyman.com/2008/04/11/javascript-loop-performance/), it should probably be written so that the length is only calculated once.

In jQuery there is a .each that you can stick a function. I like this a little better, because I don't have to type the array twice, like in the above solution.

If JavaScript supported macros it would be a piece of cake to roll your own, but sadly it does not.

So what do you guys use?

回答1:

I've started using iterators where relevant. Performance is reasonable, however more importantly it allows you to encapsulate the looping logic:

function createIterator(x) {
    var i = 0;

     return function(){
       return x[i++];
    };
}

Then to use:

var iterator=createIterator(['a','b','c','d','e','f','g']);

iterator();

returns "a";

iterator();

returns "b";

and so on.

To iterate the whole list and display each item:

var current;

while(current=iterator())
{
    console.log(current);
}

Be aware that the above is only acceptable for iterating a list that contains "non-falsy" values. If this array contained any of:

  • 0
  • false
  • ""
  • null
  • NaN

the previous loop would stop at that item, not always what you want/expect.

To avoid this use:

var current;

while((current=iterator())!==undefined)
{
   console.log(current);
}


回答2:

Small improvement to the original, to only calculate the array size once:

for(var i = 0, len = a.length; i < len; i++){ var element = a[i]; }

Also, I see a lot of for..in loops. Though keep in mind that it's not technically kosher, and will cause problems with Prototype specifically:

for (i in a) { var element = a[i]; }


回答3:

Just store the length in a variable first.

  var len = a.length;
  for (var i = 0; i < len; i++) {
    var element = a[i];
  }


回答4:

I know I'm late to the party, but I use reverse loops for loops that don't depend on the order.

Very similar to @Mr. Muskrat's - but simplifying the test:

var i = a.length, element = null;
while (i--) {
  element = a[i];
}


回答5:

You could just always use a while loop, and compute the array limit before hand.

Var max = a.length-1;
var i = 0;

while(i <= max)
{
var element = a[i];
i++;
}


回答6:

If you have many elements in the array and speed is an issue then you want to use a while loop that iterates from highest to lowest.

  var i = a.length;
  while( --i >= 0 ) {
    var element = a[i];
    // do stuff with element
  }  


回答7:

I don't use it myself, but one of my colleagues uses this style:

var myArray = [1,2,3,4];
for (var i = 0, item; item = myArray[i]; ++i) {
    alert(item);
}

like Ash's answer, this will hit issues if you've got "falsey" values in your array. To avoid that problem change it to (item = myArray[i]) != undefined



回答8:

I don't see what the problem with using a standard for(;;) loop is. A little test

var x;
var a = [];
// filling array
var t0 = new Date().getTime();
for( var i = 0; i < 100000; i++ ) {
    a[i] = Math.floor( Math.random()*100000 );
}

// normal loop
var t1 = new Date().getTime();
for( var i = 0; i < 100000; i++ ) {
    x = a[i];
}

// using length
var t2 = new Date().getTime();
for( var i = 0; i < a.length; i++ ) {
    x = a[i];
}

// storing length (pollution - we now have a global l as well as an i )
var t3 = new Date().getTime();
for( var i = 0, l = a.length; i < l; i++ ) {
    x = a[i];
}

// for in
var t4 = new Date().getTime();
for( var i in a ) {
    x = a[i];
}

// checked for in
var t5 = new Date().getTime();
for( var i in a ) {
    if (a.hasOwnProperty(i)) {
        x = a[i];
    }
}

var t6 = new Date().getTime();
var msg = 'filling array: '+(t1-t0)+'ms\n'+
          'normal loop: '+(t2-t1)+'ms\n'+
          'using length: '+(t3-t2)+'ms\n'+
          'storing length: '+(t4-t3)+'ms\n'+
          'for in: '+(t5-t4)+'ms\n'+
          'checked for in: '+(t6-t5)+'ms';
console.log( msg );

results in:

filling array: 227ms
normal loop: 21ms
using length: 26ms
storing length: 24ms 
for in: 154ms
checked for in: 176ms

So:- for in's take the longest, using the length property (which is a property and doesn't need to be calculated) is nearly as fast as storing it first - which is only a whisker slower than using an integer.
AND a for() is the usual way to loop over an array, which everyone expects and understands.

All of them add a variable to the scope they run in - i - which is a common name for this use and so shouldn't be used for other things. Storing the length first adds another var - l - to the scope, which is unnecesary



回答9:

So, first you identify the perfect javascript loop, I believe it should look like this:

ary.each(function() {$arguments[0]).remove();})

This may require the prototype.js library.

Next, you get disgustet with the arguments[0] part and have the code be produced automatically from your server framework. This works only if the ladder is Seaside.

Now, you have the above generated by:

ary do: [:each | each element remove].

This comes complete with syntax completion and translates exactly to the above javascript. And it will make people's head spin that haven't used seasides prototype integration before, as they read your code. It sure makes you feel cool, too. Not to mention the gain in geekiness you can get here. The girls love it!