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?
-
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++; }
Anders Rune Jensen : Sorry to be blunt, but I fail to see how this is an improvement. You still specify the array twice, and in your solution the environment around is polluted with two variables which scrope should not transcend the while loop construct.Jason Etheridge : The environment is going to be "polluted" anyway, given that in Javascript the scope of a variable is the enclosing function, not the block in which it is declared.Kibbee : Testing it against the link given in the question, it's at least as fast, if not faster, than any of the for loop implementations. -
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); }
Anders Rune Jensen : Yeah, I have also been thinking about using iterators. They much better encapsulate the concept of traversing something than simple loops do. But how would you in your example print all elements in the iterator?Jason Bunting : Beautiful closure sweetness. Ahh, I loves 'em.Kibbee : How do you know when you've reached the end if your iterator doesn't have a HasNext function? If you just keep on calling "iterator" per your example, you will eventually get array index out of bounds.Ash : Kibbee, Anders, I've added a simple example of how to iterate the whole list to the answer.Anders Rune Jensen : Love it. Thanks!Kibbee : Sorry, I guess i'm a little to conditioned to using languages that throw exceptions when you try to access past the end of the array to try to code something that relies on the fact that JS doesn't throw an exception when you try to do this.Ash : Kibbee, No need to be sorry, I should have added that example earlier. One of the most important things to know in Javascript is the "falsy" values (values that are evaluated as false). These are: "", null, 0, NaN, false and finally undefined. The iterator relies on undefined being returned.insin : If you liked this answer, you may be interested in http://bob.pythonmac.org/archives/2005/07/06/iteration-in-javascript/ and Mochikit's http://mochikit.com/doc/html/MochiKit/Iter.htmlManuel Ferreria : This is rather hackish. Me like it!Jani Hartikainen : Welcome to the world of Slow and Confusing. This idiom is *far* from common in JavaScript world, so people will have difficulties with your codebase if you decide to use this. If you have large loops, this approach is also *very* slow. Function calls are expensive in JS.Ash : @Jani, welcome to the world of New Ideas! This answer might help make the idiom more common. Also, performance is more than acceptable for normal day to day usage in my experience, and this depends heavily on the Javascript engine running it anyway. Function calls may be expensive, but un-maintainable Javascript costs a hell of a lot more!Jani Hartikainen : A "standard" loop is hardly unmaintainable. However I can see you understood my point ;) -
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]; }
Vincent Robert : for..in loops are used to iterate over object properties, while they seem to work for Arrays, they will also iterate over the 'length' property or any other dynamically added property. That's why it does not work well with Prototype. -
Just store the length in a variable first.
var len = a.length; for (var i = 0; i < len; i++) { var element = a[i]; }
-
And you can see a little test on the issue in: http://stackoverflow.com/questions/157260/whats-the-best-way-to-loop-through-a-set-of-elements-in-javascript#161664
-
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 }
Paul Hargreaves : the >= 0 isn't needed, just change --i to i-- -
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
-
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]; }
annakata : well I'm *very* late to the party, but this is the correct answer and should be accepted as such. For the uninitiated, the i-- clause saves a comparison (because 0 = false in JS tests). Caveat 1: reverse order! Caveat 2: readability isn't great. Caveat 3: a cached for loop is very nearly as good -
I tried Ash's solution and sadly declaring the two variables is quite tiresome in the end. I'm currently using the .each() from jquery and so far it's the best I have found. The only problem is that one can't return directly from the loop, and that break and continue is implementated as ugly idiosyncrasies (return true/false).
-
http://blogs.sun.com/greimer/entry/best_way_to_code_a
That basically covers the whole subject
Anders Rune Jensen : pretty wierd that the "while (i--)" solution is the fastest ;-) -
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!
-
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