What’s the Best Way to Write a JavaScript For Loop?

What's the Best Way to Write a JavaScript For Loop?When coding JavaScript, I find myself using the for loop fairly often. Recently, when I coded, then re-coded these drop-down menus, during the re-code I ran my JavaScript/jQuery through JSLint using the option called “The Good Parts”.

I don’t know a whole lot about JSLint, but I figured that would be a pretty good way to ensure the code was efficient, relatively future-proof, and easy to maintain (i.e. it uses best practices).

The info JSLint provided, as well as other stuff I’ve read in the past, got me thinking about the simple JavaScript for loop and how it’s customarily written.

Update (September 7, 2012): If you’re interested, you can check out a jsperf I set up that compares the original code and the final optimized version. The performance difference seems to be very small.

How It’s Typically Written

I think it’s safe to say that most beginner to intermediate JavaScript developers will write their for loops like this:

var anchors = document.getElementsByTagName("a");

for (i=0;i<anchors.length;i++){
	// do some stuff here
}

I included an extra line to collect some DOM elements to iterate over, but the loop is really what we’re focused on here. Even though this code will work just fine, how can it be improved? Well, JSLint as well as best practices for high performance JavaScript will assist us to make some small, but important improvements.

Fix the Spacing

That small example of code produces 11 error messages in JSLint using the option “The Good Parts”. One of the things JSLint will often point out is the lack of spacing around your operators. So let’s fix the spacing. Here’s how our code looks after correcting all the spacing issues:

var anchors = document.getElementsByTagName("a");

for (i = 0; i < anchors.length; i++) {
	// do some stuff here
}

Technically, I didn’t need to put a space after the semicolons, but I did it anyhow to aid readability. In addition to proper spacing around the operators, JSLint also requires a space between the closing parenthesis and the opening curly brace. All these spacing issues are, from what I understand, to help avoid using confusing code that’s prone to accidental errors or code in which errors are hard to spot.

Localize Your Variable

After fixing the spacing issues, we can now focus on another error presented by JSLint: the global variable i. Any variable not defined using the var statement in JavaScript is global in scope. This is bad practice, and it can be easily overlooked inside of such a commonly-used bit of code. So let’s make our variable local using the var keyword. We could do this a couple of ways, but the following method will suffice to make JSLint happy:

var anchors = document.getElementsByTagName("a");

for (var i = 0; i < anchors.length; i++) {
	// do some stuff here
}

Now JSlint only gives us one remaining error. (Well, technically, this code will give two other errors: The document global and the empty block, but that’s not a big deal in this illustrative example).

Don’t Use the Increment Operator

This is something that I was surprised to see. I haven’t yet read Crockford’s book so I don’t know if there’s more to this than what’s explained on the JSLint instructions page, but here’s what it says about the increment (++) operator:

The ++ (increment) and — (decrement) operators have been known to contribute to bad code by encouraging excessive trickiness. They are second only to faulty architecture in enabling to viruses and other security menaces.

My guess is that using an increment operator in a harmless for loop is not going to cause much of a problem for you. But who am I to question? So what is the alternative? Well, the increment operator is just a way of saying “add 1 to my variable”, so let’s make JSLint happy by doing just that:

var anchors = document.getElementsByTagName("a");

for (var i = 0; i < anchors.length; i += 1) {
	// do some stuff here
}

I really don’t know if this is the best and/or only way to do this, or if this is even necessary in a for loop, but it gives us the same result and JSLint likes it.

Now there are no significant errors in this seemingly harmless bit of code. But there are two more improvements that can be made that JSLint doesn’t warn us of.

Don’t Calculate the Length on Each Iteration

As the code is now, the length of anchors is calculated on each loop iteration. In a large application, and with large values and multiple loops, this can contribute to performance issues. So although in many small instances this might not matter, it is best practice to try to cache values before using them. So we can alter the code to look like this instead:

var anchors = document.getElementsByTagName("a");

for (var i = 0, j = anchors.length; i < j; i += 1) {
	// do some stuff here
}

Now the value gets calculated only once, and is stored in the variable j. I certainly have to thank the commenters in some of my previous JavaScript articles for pointing out this improvement in my loops.

Decrement the Value Instead

Assuming that you don’t care about the order in which the collected elements are looped through, you can evidently improve the performance of your loops by decrementing the value instead of incrementing it. Here’s how the new code will look:

var anchors = document.getElementsByTagName("a");

for (var i = anchors.length - 1; i >= 0; i -= 1) {
	// do some stuff here
}

Now the different parts of the loop’s instructions have been reversed and we’ve even eliminated the use of a second variable, since we know that we’re just going down to 0. Of course, you might have a case where decrementing your loop would not work, so this is just something to consider should the situation allow for it. Notice also that I’m subtracting one from the starting value and letting the loop go down to zero, to account for zero-based indexing.

Final Thoughts

So that’s it, there’s five practical improvements made to a simple for loop, and more importantly, some underlying principles that can help you to write cleaner and more efficient code on a larger scale.

As a side point, there aren’t many examples online or otherwise that will present a for loop using the tips described above, but I think it would be good if most developers adopted these practices if they do indeed contribute to better performance, readability, and maintainability.

I should point out — as I often do when I write about JavaScript — that I don’t consider myself an expert in this area, so if you have any corrections or supplementary information to contribute to this topic, please do so in the comments. And by all means, do the necessary research before you take my word as gold. I’m still learning, and I’m happy to correct any mistaken views.

Advertise Here

34 Responses

  1. Your last example for “Decrement the Value Instead” will cover values from 1 to N instead of 0 to N-1.

  2. My preferred way is:

    
    var anchors = document.getElementsByTagName("a");
    var j = anchors.length;
    for (var i = 0; i < j; i++) {  
         // do some stuff here  
    }  
    

    That’s how is I’m used to do it in other languages too, although I usually don’t declare the i variable in-line like that. The reason I put anchors.length in a variable j is that in PHP it allows for faster code execution and it is something that stuck. I must honestly say I never did tests in JS. My guess is it won’t matter that much since you’re accessing a property value and not executing a method

    I do not agree about the increment and decrement operators. Bad or good architecture is up the programmer and IMHO there is nothing tricky about i++ or ++i

  3. what about :

    
    for(var i = anchors.length; i--;) {
    
    }
    

    it spares one evaluation

    • Very nice!

      – cached & localized variable
      – tiny code

      I’m sticking with this method from here on out! :)

    • Josh:

      This is a nasty way to do this and is guaranteed to confuse future developers who look at your code. By putting the decrementer in the evaluation statement, you’re counting on javascript interpreting the numbers 0 and below as “falsy” values in order to break out of the loop.

  4. Hello,

    I’ll stick to the “i++”, and I have suggestion for the “Decrement the Value Instead” example. Wy not use “while” instead ? e.g.

    
    var i = anchors.length;
    
    while (i--)
    {
        // do some stuff here
    }
    
  5. It is always best to cache the iterator (anchors.length) due to the reasons given above, though it is especially important when dealing with HTMLCollection objects (as returned by document.getElementsByTagName).

    This is because an HTMLCollection is live, i.e. it is updated whenever the DOM itself is modified – thus if you were to execute some code within the loop body which modified the anchors in the DOM, you could have undesirable behaviour. At worst case, if you were creating a new anchor with each iteration, the length of the collection would increase if you did not cache it – potentially causing an infinite loop.

  6. D Israel:

    Good article, but there’s some important distinctions here. You say:

    the increment operator is just a way of saying “add 1 to my variable”

    That’s not exactly correct. The i++ syntax says “execute this statement, *THEN* add 1 to my variable”. (And the ++i syntax says “add 1 to my variable, *THEN* execute this statement”.

    Sounds like nitpicking? Not exactly. In the context of your code, it doesn’t make much difference (the part of code after the second semi-colon is executed after each iteration). However, consider the following:

    
    var x = 7;
    var i;
    
    document.write(" =================== ");
    
    for (i=0; i<x; i++) {
    	document.write(i + "");
    }
    
    document.write(" =================== ");
    
    for (i=0; i<x; ++i) {
    	document.write(i + "");
    }
    
    document.write(" =================== ");
    
    for (i=x; i>0; i--) {
    	document.write(i + "");
    }
    
    document.write(" =================== ");
    
    for (i=x; i>0; --i) {
    	document.write(i + "");
    }
    
    document.write(" =================== ");
    
    for (i=x; i--; ) {
    	document.write(i + "");
    }
    
    document.write(" =================== ");
    
    for (i=x; --i; ) {
    	document.write(i + "");
    }
    
    document.write(" =================== ");
    
    i = x;
    while (i--) {
    	document.write(i + "");
    }
    
    document.write(" =================== ");
    
    i = x;
    while (--i) {
    	document.write(i + "");
    }
    

    Note the number of iterations can differ with implementation… This is confusing because many people read “i++” and “++i” as fundamentally the same (similarly “i–” and “–i”), but they aren’t.

    Further, the values of i are different in different implementations (even amongst the ones with same number of iterations). You did mention the caveat about whether or not order matters, but in your example, the values of i (that we loop through) are different, and why are you iterating through an array if you’re not using i as an index into the array?

  7. Kozie:

    What about

    
    for (var i in myArray) {
      // Do some stuff here.. again :P
    }
    

    ?

  8. Greg:

    How about

    
    for(var i in anchors) {
        // Do something with i.
    }
    

    Way more simpler, no?

  9. I’m with the last two guys. Javascript’s for in and PHP’s foreach are the loops I use most often.

  10. +1 to @jpvincent and @Olivier Laviale.

    On element collection/arrays that can’t contain ‘falsy’ items, my favorite way is:

    
    for (var i=0, item; item = someArray[i]; i++) {
    	alert(item);
    }
    

    Which is like a “foreach” and still preserves the order of elements.

  11. Since in my University, we were taught to use the “++” increment for loop, and this is the first time I see that “+=” can replace “++”. Awesome knowledge Louis.

  12. GS:

    I’ve always found

    
    for (i = size; --i >= 0; )
    

    to be readable and correct (so long as i is signed in a language that supports unsigned types)

    This was slightly higher performance in low-level code (C) when cache lines weren’t a factor, as machine code produced can be something like:

    LOOP_START :
    decrement;
    jump-if-less-than-zero END_LOOP;
    loop contents ;
    goto LOOP_START;
    END_LOOP :

    which is simpler than the comparisons and jumps required otherwise.

    I got into this habit 20 years ago, though. No idea whether this holds when CPU cache lines are put into the mix. Optimizing JS compilers like V8 might be able to demonstrate a microbenchmarkable improvement (or not)..

  13. dale:

    like @jpvincent, though I tend to stick what i’m checking against outside the for loop declaration:

    var i = array.length;
    for ( ; i–; ) {
    // do some code
    }

  14. I have question related to JavaScript Optimization.
    Whenever web page is rendered , its all css + script files are also loaded hence effect bandwidth etc.
    If I code JavaScript in meaningful manner ( popup.js serve popup .. slideshow.js serve slideshow etc etc) then on each round trip it effects performance .. And if I write whole JavaScript code in single file ( messy code ) it will be difficult for other to understand the flow of code etc … and if I myself review the code after 3-4 month it will be strange for me too.
    So how to optimize such issue ..

  15. Actually caching a length of collection is not for performance.
    It’s for correctly working your code, James Shuttler aleready said.

    And

    
    for(var i=0;i<10;i++) {
      // do something
    }
    

    is not good style for javascript.

    Because js has fuction scope.
    You should write like this.

    
    var i;
    for(i=0;i<10;i++) {
      // do something
    }
    
  16. Tamás Márton:

    Thanks for the detailed and organized help!

  17. John:

    I am surprised to see the notation about ++ being a ‘bad coding practice’ ..

    re: “The ++ (increment) and — (decrement) operators have been known to contribute to bad code by encouraging excessive trickiness. They are second only to faulty architecture in enabling to viruses and other security menaces.”

    This is inaccurate… for most coding styles of ppl who write i++ i guess it doesn’t matter.. what *does* matter is that 99% of ppl use i++ in their loops. ‘THAT’ is a bad coding practice! It should have been taught in school to use ++i (the pre-increment) form. ‘Pre-increment’ has fewer machine instructions to achieve (it does not have the ‘store’ the original value before incrementing it’). Maybe the newer chips have eliminated the step, but i don’t think so.. If you want to maximize a loop do some research on ++i pre-increment at the machine code level and see what the ‘current’ science of it is (in terms of assembly / register instructions).

  18. Thanks for this. I’ve been curious about ++ vs — for a while now. Oh, I also want to point out that the article you linked to is actually originally from StackOverflow (http://stackoverflow.com/questions/3520688/javascript-loop-performance-why-is-to-decrement-the-iterator-toward-0-faster-t). Websites like the one you linked to like to steal their content.

    • Nice catch Levi, I’ve changed the link to the SO thread instead. I must have found that via a Google search and didn’t bother looking at it carefully enough. Thanks for pointing it out.

  19. Interesting note: ++ is actually faster in Chrome, and += is faster in IE10.
    8)

    http://jsperf.com/loop-inc-test

  20. Gr:

    very nice, ill start writing my for loops differently now

  21. Wing:

    try this:

    var i = 0,
    len = arr.length;
    for (i; i < len; i++) {
    //do something
    }

  22. Frank:

    I could be wrong about this but I thought lenght was a property not a function so what are you actually calculating? My thoughts are the the length property is already a memory location, so creating another variable and assigning a value to it such as the length property is actually a pointer to the original location where the length property is stored so you are not gaining anything except using more memory? Just trying to get educated.

  23. This post covered everything regarding iteration. Thanks for detail level explanation.

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field. If you use keywords, your comment will be deleted, or your name will be replaced with the alias from your email address. No foul language, please. Thank you for cooperating.

Instructions for code snippets: Wrap inline code in <code> tags; wrap blocks of code in <pre> and <code> tags. When you want your HTML to display on the page in a code snippet inside of <code> tags, make sure you use &lt; and &gt; instead of < and >, otherwise your code will be eaten by pink unicorns.