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.