for vs. do {} while

While developing Sylvester, I’ve read up a little on how to make JavaScript perform as best it can. One of the recommendations given in this Andy King article and elsewhere is that you should use do {} while instead of for for looping purposes. I’m not singling out King for criticism, but I want to clarify some of what he says.

He does point out that the use of this construct:

do {
  // Code goes here
} while (--i);

depends on the starting value of i being greater than zero. He doesn’t point out that by putting the while first, you can accommodate zero starting values and get exactly the same sequence of i values.

while (i--) {
  // Code goes here
}

Now the loop will not execute if i starts at zero and you won’t get an infinite loop. Note the switching of the position of the decrement operator to ensure the right values are passed into the loop. King does not clarify this and suggests that the following will do the same thing:

do {
  // Code goes here
} while (--i);    // pre-decrement
do {
  // Code goes here
} while (i--);    // post-decrement

Say i begins at 3 in both cases. The first will iterate the loop with the values 3, 2 and 1: pre-decrementing 1 evaluates to 0 and the loop stops. But, post-decrementing 1 evaluates to 1 so the loop will run one more time in the second case.

Finally, onto the issue of speed. (These findings are based on testing in Firefox 2.0 using Firebug.) Yes, while is faster than for if you can use the decrement operator as a conditional statement. The efficiency comes from the fact that you’re using the same command to change the iteration value and check whether we should loop again, so it’s only useful for situations where you can count down to zero rather than needing to count upwards. Also, if you need to use the iteration counter in the loop and you need to count forwards, you need to do something like this:

var n = 10, k = n, i;
do {
  i = k - n;
} while (--n);

which, it turns out, is slower than using a for loop to achieve the same thing:

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

So to sum up: if you can afford to count backwards to zero, use a while loop as this will involve the fewest commands to actually make the loop run. If you need to count forwards or end on anything other than zero, use a for loop and cache as many things as you can. For example, write

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

instead of putting the array length statement directly inside the for statement. Retrieving a property from an object takes longer than retrieving a primitive value, so this is the most efficient way to do things.