Structurally, a while statement is constructed much like an if statement: a main statement encloses a block of substatements that are executed only when a given condition is true:
while (condition) { substatements }
If condition is true, substatements are executed. But, unlike the if statement, when the last substatement is finished, execution begins anew at the beginning of the while statement (that is, the interpreter "loops" back to the beginning of the while statement). The second pass through the while statement works just like the first: the condition is evaluated, and if it is still true, substatements are executed again. This process continues until condition becomes false, at which point execution continues with any statements that follow the while statement in the script.
Here's an example of a very simple loop:
var i = 3; while (i < 5) { trace("x is less than 5"); }
The example reliably represents the correct syntax of a while loop but is most likely in error. To see why, let's follow along with the interpreter as it executes the example.
The interpreter starts with the statement before the while statement, var i = 3, which sets the variable i to 3. Because the variable i is used in the test expression of the loop, this step is often called the loop initialization. Next, the interpreter begins executing the while statement by resolving the test expression: i < 5. Because i is 3, and 3 is less than 5, the value of the test expression is true; so, the interpreter executes the trace( ) statement within the loop, sometimes called the loop body.
With that done, it's time to repeat the loop. Once again, the interpreter checks the value of the test expression. The value of the variable i has not changed, so the test expression is still true and the interpreter executes the trace( ) statement again. At this point, the loop body has finished executing, so it's time to repeat the loop. Guess what? The variable i still has not changed, so the test expression is still true and the interpreter must execute the trace( ) statement again, and again, and again, forever. Because the test expression always returns true, there's no way to exit the loop—Flash is trapped forever in an infinite loop. In ActionScript, an infinite loop causes an error, as we'll see later.
Our loop is infinite because it lacks an update statement that changes the value of the variable used in the test expression. An update statement typically causes the test expression to eventually yield false, which terminates the loop. Let's fix our infinite loop by adding an update statement:
var i = 3; while (i < 5) { trace("x is less than 5"); i++; }
The update statement, i++;, comes at the end of the loop body. When the interpreter goes through our loop, it executes the trace( ) statement as before, but it also executes the statement i++;, which adds 1 to the variable i. With each iteration of the loop, the value of i increases. After the second iteration, i's value is 5, so the test expression, i < 5, becomes false. The loop, therefore, safely ends after two iterations.
Our loop's update statement performs a fundamental loop activity: it counts. The variable i (called a counter) runs through a predictable numeric sequence—perfect for methodical tasks such as duplicating movie clips or accessing the elements of an array. Here we duplicate the square movie clip five times without using a loop:
// Name each new clip sequentially and place it on its own depth duplicateMovieClip("square", "square1", 1); duplicateMovieClip("square", "square2", 2); duplicateMovieClip("square", "square3", 3); duplicateMovieClip("square", "square4", 4); duplicateMovieClip("square", "square5", 5);
And here we perform the same operation with a loop:
var i = 1; while (i <= 5) { duplicateMovieClip("square", "square" + i, i); i++; }
Imagine the difference if we were duplicating square 100 times!
Loops are marvelously useful for manipulating data, particularly data stored in arrays. Example 8-1 shows a loop that displays all the elements of an array to the Output window. Note that the first element is number 0, not number 1.
var people = ["John", "Joyce", "Margaret", "Michael"]; // Create an array var i = 0; while (i < people.length) { trace("people element " + i + " is " + people[i]); i++; }
The result in the Output window is:
people element 0 is John people element 1 is Joyce people element 2 is Margaret people element 3 is Michael
Notice that the variable i is used both in the test expression and as the array index number, as is typical. Here we use i again as an argument for the charAt( ) function:
var city = "Toronto"; trace("The letters in the variable 'city' are "); var i = 0; while (i < city.length) { trace(city.charAt(i)); i++; }
The Output window shows:
The letters in the variable 'city' are: T o r o n t o
Finally, instead of dissecting data, we use a loop to construct a sentence from a series of words stored in an array:
var words = ["Toronto", "is", "not", "the", "capital", "of", "Canada"]; var sentence; var i = 0; while (i < words.length) { sentence += words[i]; // Add the current word to the sentence // If it's not the last word... if (i < words.length - 1) { sentence += " "; // ...tack on a space } else { sentence += "."; // ...otherwise, end with a period } i++; } trace(sentence); // Displays: "Toronto is not the capital of Canada."
Nearly all loops involve some kind of counter (sometimes called an iterator or index variable). Counters let us cycle sequentially through data. This technique is particularly convenient when we determine the counter's maximum limit using the length property of the array or string we want to manipulate, as we did in the preceding example.
It's also possible to create a loop whose end point doesn't depend on a counter. As long as the test expression of the loop eventually becomes false, the loop will end. Here, for example, we examine the document level stack of the Flash Player to determine the first vacant level:
var i = 0; while (typeof eval("_level" + i) = = "movieclip") { i++; } trace("The first vacant level is " + i); // Now load a movie into the vacant level, knowing it's free loadMovieNum("myMovie.swf", i);
For more information on document levels, see Section 13.4 in Chapter 13.