Selection statements may be the most used of all JavaScript statements, but repetition statements make up the biggest time slice of the total running time of your program. On average, repetition statements (or loops) will take up 95 to 99 percent of the total running time of any given program. Because of this fact, it is necessary not only to write working loops, but to write efficient loops. This is especially necessary with an interpreted language such as JavaScript because the interpretation tends to run slower than identical natively compiled programs.
The simplest type of repetition statement, or loop structure, is the while loop. A while loop is adequate for meeting all of your looping needs. The syntax for a while loop is very simple:
while( <condition> ) { <statements> }
A while loop executes all of the statements between curly braces over and over again until the condition is evaluated to false. Just like with the if statement, the curly braces are optional if and only if there is a single statement within the loop body. Take a look at the following example, which creates a table with five rows:
<html> <head> <title> JavaScript Professional Projects - Repetition Statements - while </title> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 2: Repetition Statements - while</font> </center> <br><br> <p> <table width="85%" border="1"> <script language="JavaScript"> <!-- var n = 1; while( n <= 5 ) { document.write( "<tr><td>" + "This is row #" + n + "</td></tr>" ); n++; } // --> </script> </table> </p> </body> </html>
The while loop in the body runs as long as the variable n is less than or equal to five incrementing ns each time through the loop. The loop runs a total of five times and creates a new row in the table each time. The last line in the body of the loop, n++;, is very important. If that one line were not there, the condition would never evaluate to false and would cause the loop to run forever—an infinite loop. You can tell if you have written an infinite loop because your computer will appear to slow down, and the Web page will never be displayed in the browser. The only way to stop an infinite loop is to close your browser or, if you are unable to close your browser, hit Alt + F4 in Windows or Command + Option + Escape in Mac OS.
The alternating row color example presented earlier would be an excellent candidate for the while loop.
<html> <head> <title> JavaScript Professional Projects - Alternating row </title> <script language="JavaScript"> <!-- var rowNumber = 1; function getColor() { var color; switch( rowNumber ) { case 0: color = "gray"; break; case 1: color = "white"; break; case 2: color = "blue"; break; case 3: color = "green"; break; case 4: color = "red"; break; } rowNumber = ( rowNumber + 1 ) % 5; return( color ); } // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 2: Alternating row background colors</font> </center> <br><br> <p> <table width="85%" border="1"> <script language="JavaScript"> <!-- var n = 1; while( n <= 15 ) { document.write( "<tr bgcolor='" + getColor() + "'>" ); document.write( "<td>Row number " + n + "</td></tr>" ); n++; } // --> </script> </table> </p> </body> </html>
With the while loop, not only does the Web page become much smaller as far as the amount required to download, but it also becomes much more flexible. If you wanted a table with more or fewer rows, all you would have to do is change the condition in the while loop. This is especially useful if you don't know how many rows are required before the page is loaded. Take a look at the following code fragment for a simple example of dynamic row counts:
var n = 1; var totalRows = Math.random() * 20 + 1; while( n <= totalRows ) { document.write( "<tr bgcolor='" + getColor() + "'>" ); document.write( "<td>Row number " + n + "</td></tr>" ); n++; }
If you replace this code fragment for the script in the above example, you will get a randomly generated number of rows—anywhere from 1 to 21.
The do-while statement is very similar to the regular while statement. The condition in while loops is tested before the body of the loop is run. This means that it is possible for the loop not to run at all. The difference in the do-while loop is that the condition is tested after the loop body has run. This ensures that the loop will run at least one time before the condition statement is reached. Here is the syntax for the do-while statement:
do { <statements> } while( <condition> );
One important difference in the syntax is the fact that the do-while statement ends in a semicolon and the while statement does not. The semicolon at the end of the do-while loop is needed to set the while portion off from the next line of code and to make your source easier to read.
A for loop is slightly more complicated than a while loop because it takes three operands and can create/update variables. A while loop can do everything a for loop can do. Likewise, everything a for loop can do is also possible with a while loop. Choosing between a for or while loop is really up to the programmer, as there is no inherit benefit from using one instead of the other. The syntax of a for loop is as follows:
for( <declaration> ; <condition> ; <increment> ) { <statements> }
The declaration part of the for loop is where you can declare and initialize the control variable for the loop. The condition part of the for loop is identical to the condition portion of the while loop and will cause the loop to run until evaluated to false. The increment portion of the for loop is where the control variable is updated. All three parts of the for loop header are optional, but the semicolons must always be present. Just as with the while loop and if statement, the curly braces are optional if and only if there is a single statement in the body of the loop.
The order in which the portions of a for statement are executed is very important to how a program behaves. When the loop is reached, the declaration portion of the statements is executed and then the condition is checked. If the condition evaluates to true, the loop body is run and the increment portion is executed. Once again, the condition is checked and if it evaluates to true, the body and increment portions of the loop are each executed. The whole process continues until the condition evaluates to false.
To illustrate the ease of switching between for and while loops, here is the alternating row color example with for loops:
<html> <head> <title> JavaScript Professional Projects - Alternating row </title> <script language="JavaScript"> <!-- var rowNumber = 1; function getColor() { var color; switch( rowNumber ) { case 0: color = "gray"; break; case 1: color = "white"; break; case 2: color = "blue"; break; case 3: color = "green"; break; case 4: color = "red"; break; } rowNumber = ( rowNumber + 1 ) % 5; return( color ); } // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 2: Alternating row background colors</font> </center> <br><br> <p> <table width="85%" border="1"> <script language="JavaScript"> <!-- var totalRows = Math.random() * 20 + 1; for( n = 1 ; n <= totalRows ; n++ ) { document.write( "<tr bgcolor='" + getColor() + "'>" ); document.write( "<td>Row number " + n + "</td></tr>" ); } // --> </script> </table> </p> </body> </html>
The examples produce identical results. It is up to you to choose which loop you want to use.
One thing that you can do with a for loop that's not so easy to do with a while loop is to declare variables that will only be used within the scope of the loop. In the preceding example, the variable n was part of the declaration portion of the for loop. This variable will only be available as long as the loop is running. As soon as the loop ends, the variable is "forgotten" as the memory it occupied is freed. You are not limited to only one variable declaration in the for loop. In the same example, it would be possible to declare the variable totalRows within the declaration portion of the for loop.
for( n = 1, totalRows = Math.random() * 20 + 1 ; n <= totalRows ; n++ ) { document.write( "<tr bgcolor='" + getColor() + "'>" ); document.write( "<td>Row number " + n + "</td></tr>" ); }
This loop and the one used in the previous example are nearly identical. A comma-separated list of variables in the declaration portion of the for loop means that each will be initialized before the loop begins. The only drawback to the second approach is that the variable totalRows will no longer be available after the loop completes. You may also have a comma-separated list of increments in the increment portion of the for loop.
for-in loops are used to easily iterate through a list of items such as an array or properties of an object. Here is the syntax for a for-in statement:
for( <variable> in <object> ) { <statements> }
In the for-in loop, "variable" is the name of a new variable that will hold the next element of "object" during each pass through the loop. This concept is best illustrated with an example.
<html> <head> <title> JavaScript Professional Projects - Repetition Statements - for-in </title> <script language="JavaScript"> <!-- var daysArray = new Array( "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ); // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 2: Repetition Statements - for-in</font> </center> <br><br> <p> <script language="JavaScript"> <!-- for( day in daysArray ) { document.write( daysArray[day] + "<br>" ); } // --> </script> </p> </body> </html>
In this example, daysArray is an array holding the days of the week. The for-in loop in the body of the Web page iterates through each element in the array and prints the value of the array element. One advantage of using a for-in loop to iterate through arrays is that you do not need to know the size of the array. This allows you to write faster and more efficient code.
for-in loops will be covered in depth in Chapter 3, "Arrays and Strings" and in Chapter 5, "Object-Oriented JavaScript."
Sometimes it is necessary to alter the flow of a loop from within the loop itself. For example, if erroneous data is encountered while looping through all the elements in a form, the break command will allow the loop to be prematurely exited. A situation in which you might use the break command would be when a loop is finding the sum of an array of integers and encounters an element that is not a number.
var total = 0; for( number in theArray ) { if( !isNaN( theArray[number] ) ) { total += theArray[number]; } else { break; } }
As soon as the loop encounters an array element that is not a number and, consequently, cannot be added to the total, the loop breaks. If all of the array elements are numbers, the loop will successfully iterate through the entire array, adding each element to the total.
Another way to handle the erroneous array elements would be to simply skip each one that is not a number. The continue command tells the loop structure to break out of the current loop, but continue as if everything was fine. The example above could be rewritten as
var total = 0; for( number in theArray ) { if( !isNaN( theArray[number] ) ) { total += theArray[number]; } else { continue; } }
This program segment would find the sum of all of the numbers in an array, ignoring anything that is not a number.
The break and continue commands are most often used for error checking and error recovery while processing data in loops.
Because so much of the time that a program is running is taken up by executing repetition statements, a lot of study has gone into making them as efficient as possible. The total running time of a program can be greatly improved by decreasing the number of instructions inside a loop, even if those instructions are simply moved outside the loop structure.
There are two techniques for the optimization of loops: code motion and reduction in strength. These techniques are very advanced concepts that are usually discussed in books on compiler writing. Feel free to consider this section optional reading. If, on the other hand, you want to know even more than is presented here, I would recommend the book Compilers: Principles, Techniques and Tools by Alfred V. Aho.
One of the simplest things you can do to decrease the amount of time spent in loops and improve the runtime of your programs is to move constant instructions outside of a loop. The easiest way to do this is to identify statements in the body of the loop that do not change as the loop runs, such as declarations and comparisons. To understand this process, take a look this example of a bad loop:
var i = 0; var limit = 57; while( i <= limit - 2 ) { var pi = 3.14; if( new Date().getDay() > 0 ) document.write( pi * i + "<br>" ); i++; }
There are three places where this loop can be improved. First of all, the quantity limit – 2 does not need to be evaluated each time through the loop. Secondly, the variable pi does not change throughout the program, so it can be moved outside of the loop. Lastly, the if statement creates a new Date object, then gets the day value and compares it to a literal—this does not need to be done every time through the loop. A better version of the same program would be
var i = 0; var limit = 57; var pi = 3.14; var t = limit - 2; var show = new Date().getDay() > 0; while( i <= t ) { if( show ) document.write( pi * i + "<br>" ); i++; }
These three changes will probably not noticeably change the runtime of your program, but if all these optimizations are applied to each of your loops, you will see a difference—especially on slower computers.
The other type of optimization, reduction of strength, might not be quite so obvious. Replacing complex operations with simpler ones inside your loops can have surprising effects on the amount of time it takes for your program to run. Here is an example program segment that would be a good candidate for reduction in strength:
for( i = 0 ; i < 100 ; i++ ) { document.write( "2^" + i + " = " + Math.pow( 2, i ) + "<br>" );
This rather straightforward loop calculates and displays the first 50 powers of two. The Math.pow() statement in particular is very costly in time. An alternative to calling this costly method 50 times is to use the left shift operator (<<). Here is the same code segment rewritten with reduction in strength applied:
for( i = 0 ; i < 100 ; i++ ) { document.write( "2^" + i + " = " + ( 1 << i ) + "<br>" ); }
The left shift operator is much less costly as far as its time requirements. Unfortunately, the left shift operator is only useful when multiplying by powers of two. Although the reduction in strength technique of loop optimization is not as common or easy to use as code motion, it generally yields more noticeable results.