CodeinWP CodeinWP

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.

43 Responses

  1. Seamus says:

    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. jpvincent says:

    what about :

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

    it spares one evaluation

    • Daniel Hug says:

      Very nice!

      – cached & localized variable
      – tiny code

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

    • Josh says:

      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.

      • Bryan says:

        The idea that eloquently written code might, “confuse other developers” has always been laughable to me. A fellow dev should smile and learn, not whimper.

        JavaScript is an insanely powerful language that all too often gets stripped back to inferior, over simplified structures because, “too confusing”. Such a shame.

        For those still concerned, there are projects like http://eder.us/projects/jbasic/ :p

  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 says:

    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 says:

    What about

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

    ?

  8. Greg says:

    How about

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

    Way more simpler, no?

  9. bfred.it says:

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

  10. Elad Ossadon says:

    +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. idraki says:

    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 says:

    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 says:

    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. anasanjaria says:

    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. ruwin126 says:

    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 says:

    Thanks for the detailed and organized help!

  17. John says:

    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 says:

    very nice, ill start writing my for loops differently now

  21. Wing says:

    try this:

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

  22. Frank says:

    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. shawpnendu says:

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

  24. Frank says:

    As a trainer and developer working over ten years with JavaScript. I’ve seen a lot of silly mistakes, quite some tough mistakes and a couple of whoa-what-are-you-doing mistakes, but suggesting not to use i++; anymore is just silly. If you work with a professional team of developers who know their stuff and thus know the language they’re programming in, doing an increment is perfectly fine.

    It’s the same with the for-loop where you declare the variable up front, why would you do that? Again, know your stuff and stop protecting you and your teammates from hypothetical mistakes. It’s time-consuming and quite frankly, belittling and insulting to your team. It’s -silly-. Crockford’s coding style is not holy.

    Here’s a speakerdeck which has this opinion and much more: https://speakerdeck.com/anguscroll/the-politics-of-javascript

  25. Marco Bonelli says:

    When you say “Don’t Calculate the Length on Each Iteration” and “As the code is now, the length of anchors is calculated on each loop iteration” you’re totally wrong.

    Doing this:


    for (var i=0; i<anchors.length; i++) {...}

    does not calculate the length at all. The length property of an object (in this case an array) is only a number. It isn’t calculated, it’s stored in the object itself, so reading the length property is exactly the same thing as assigning it to a variable and then reading it from that variable (which would only be a waste of memory).

    • James says:

      Yes, the word “calculated” is wrong – but I’m sure what he means is that it is RESOLVED (not calculated) on each iteration (because of the dot). It’s faster to first store it into a variable.

    • Old post, so I definitely used the wrong wording (but I’d probably make such mistakes today too).

      I agree with James, as I understand, it’s faster to store it in a variable. In fact, here are a few JS Perf tests:

      http://jsperf.com/caching-length-vs-not-caching-length
      http://jsperf.com/array-length-vs-cached
      http://jsperf.com/arrays-caching-length-or-not

      I created the first one, just now, but the others are probably more reliable. From my running of those, it looks like the version of the code that caches the length is always faster. I haven’t seen the non-cached version win the test yet.

      • Caue Rego says:

        first of, thanks for the article. even if it is confirmed as outdated, to my old programming skills that was an interesting read nevertheless. and, more importantly, thought provoking.

        now for the non-properly-interrogation-marked questions… (lack of text editing)

        http://jsperf.com/array-length-vs-cached actually gave me ( Chrome 56.0.2924 / Mac OS X 10.11.6 ) the cached version 26% slower (3,763,040 ±13.50% vs 5,016,621 ±12.13% from the not-cached version). twice. but both of the other 2 links and http://jsperf.com/array-length-vs-cached/54 gave me cached version running faster while non-cache would go anywhere from 20% to 66% slower. and, on the second run, there was basically no difference in any of them. every test was “fastest”. oddly enough, cached with –i and just 2 for arguments was 13% slower.

        looks like, at least nowadays, there’s more to it than just “cached is faster”. I think it comes at no surprise that newer js engines would eventually optimize that one out.

        also, jslint don’t even recognize for anymore:

        JSLint does not recommend use of the for statement. Use array methods like forEach instead. The for option will suppress some warnings. The forms of for that JSLint accepts are restricted, excluding the new ES6 forms.

        maybe those this whole article needs to be re-thinked. I sure need to do it for my own, as I just learned of jslint today.

        ps: sad those comments don’t allow markdown! too lazy to html. ;P

  26. Sheryl says:

    Nice article. I enjoyed the reminder of your last 3 points.
    Of course, these performance differences will rarely be felt, it’s nice to have them in one’s back pocket for when it really does matter. Readability generally triumphs.

    In the section “Decrement the Value” ..

    It looks like here is a typo where the number 0 has been written as a lower case o instead.
    “..just going down to o”.

    I wonder if that performance boost would be be any different if one substituted i >= 0 with a i , where the index is adjusted appropriately to stop at 0.
    Is checking for a falsey value of plain i any different than checking i !== 0 or i > 0 .

    • Hmmm, actually, the “0” is really a zero. It’s just that the font makes it look very o-ish. The code examples use a different font, so the zero has a line through it, like it should.

  27. How can you optimize the given JavaScript for loop code snippet to improve performance by avoiding the calculation of the anchors’ length on each iteration?

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field and deep URLs are not allowed in the "Website" field. If you use keywords or deep URLs, your comment or URL will be removed. No foul language, please. Thank you for cooperating.

Markdown in use! Use `backticks` for inline code snippets and triple backticks at start and end for code blocks. You can also indent a code block four spaces. And no need to escape HTML, just type it correctly but make sure it's inside code delimeters (backticks or triple backticks).