Previous Contents Next
7. Loops and Arrays

Unless told otherwise, a script executes its statements from top to bottom, one time through. When if statements are included in a script, this pattern will vary a little, with branching taking place before the script again continues on its top-to-bottom journey. At times, though, you may need to run a particular piece of code over and over again--to iterate, or loop through, the code--until some condition is met, before continuing. This is where program loops come into play.

The "for" Loop

One way to repeat an operation is with the for loop. Look at the following code and button:

<SCRIPT>
function ShowAlert (HowMany)
{
    for (var i = 1; i <= HowMany; i++) {
        alert ("\nThis is message #" + i )
    }
    alert ("\nThanks for your patience.")
}
</SCRIPT>


<FORM>
<INPUT TYPE=BUTTON VALUE="Alert"
onclick = "ShowAlert (5)" >
</FORM>


The onclick event handler in the button calls a function named ShowAlert and passes it the number 5. In the function, the number is received as variable HowMany, and the function displays an Alert box that many times, ending with a "thank you" message. It's not necessary to use five different alert statements; you can simply execute the alert command five times inside a for loop.

The general formal of the for statement is:

for (initial expression; conditional expression; update expression) {
    ...do this if condition is true...
}

The first line identifies this statement as the beginning of a for loop and establishes the number of times the loop will be iterated. Following this statement, in braces, are the statements to be executed repeatedly.

The initial expression of the for statement is executed the first time (only) that the loop is entered. This expression creates and initializes a variable that will be used as a counter to keep track of how many times the loop has been run. In the example script, variable i is declared and initialized to 1 (var i = 1). The counter will begin counting with 1.

The conditional expression normally involves a check of the counter established in the initial expression. If the conditional expression is evaluated as true, then the loop continues--the statements enclosed in the braces are executed. If the expression evaluates to false, then the loop ends and execution picks up at the statement following the closing brace. In the example script, the conditional test (i <= HowMany) asks: "is variable i less than or equal to the value of variable HowMany." (Recall that this value was passed to the function and gives the number of times to display the Alert box--5 in this instance). If this test is true, then we haven't yet exceeded the total of 5, so the statements in the braces are executed. Repeatedly, the statements are run and the condition test is made until the condition evaluates to false.

The update expression is what increments the counter. The counter is updated following execution of the statements in the loop, and is updated each time through the loop. In the example, the update expression is an arithmetic operation that adds 1 to variable i (i++). Eventually, i will be incremented to a value that makes the conditional expression false (i will become greater than 5 in the example), and the loop will end. At this point, execution jumps around the for loop and continues with the statement (if any) following the closing brace.

In the example, there is one statement inside the for loop. This statement displays an Alert box with a message and with the value of variable i, the loop counter. The script will display this Alert box five times (until counter i is greater than 5); then, it will skip out of the loop and display a final Alert box thanking users for their patience.

When you are writing for loops you must exercise great care to make sure that you are creating conditions that actually will terminate the loop. If you don't, then a loop could go on forever, leaving you to grow old and die before the computer wore out. In the example, if you mistakenly typed the update expression as i-- rather than i++, you would have to abort the browser to get the loop to stop. Nothing would be added to the counter so it would never reach 5. (With patience, though, you could get to see Alert box -1,000,000).

The "while" Loop

A while loop performs similar iteration to a for loop; its construction, though, is different. The general format of a while loop is:

while (conditional expression) {
    ...do this if condition is true...
}

As long as the conditional expression is true, the statements between the braces are executed. When the conditional expression becomes false, the braced statements are skipped over and the next statement is sequence is executed.

Although there is no required counter or update expression in a while loop, you still must provide for (1) an initial condition--prior to the loop--which makes the conditional expression true, and (2) a terminal condition--inside the loop--which makes the conditional expression false. In other words, you need to set conditions for the loop to begin and for it to end.

You can write a while loop that works like the above for loop and meets these requirements:

function WhileLoop( )
{
    var i = 1
    while (i <= 5) {
        alert ("\nThis is message #" + i)
        i ++
    }
    alert ("\nThanks for your patience.")
}

Here, variable i is declared and initialized to 1 prior to the beginning of the loop; the loop continues to execute as long as i is less than or equal to 5; and, variable i is incremented by 1 each time through, and at the end of, the loop. It is important that the counter be incremented inside the loop, else the condition for terminating the loop is never reached.

A while loop, though, is normally used in situations where no counters are involved. If you know that a loop is going the be iterated a fixed number of times, then use a for loop; it's designed for that purpose. Use the while loop for other kinds of condition tests, like the following:


function PickEm ( )
{
    var Guess = "0"
    while (Guess != "3") {
        Guess = prompt ("Guess a number between 1 and 5 to end this loop.", "")
    }
    alert ("\nGood guess!")
}

<FORM>
<INPUT TYPE=BUTTON VALUE="Guess a Number"
onclick = "PickEm ( )" >
</FORM>


The button calls the PickEm ( ) function to check whether you picked the correct number to end the loop. First, variable Guess is initialized to "0". This ensures that the condition test in the while statement will be true when the loop is entered the first time. The condition test checks to see if variable Guess is not equal to (!=) "3," which is the number that has to be entered in the Prompt box for the loop to end. Since this is true on entry to the loop (Guess = "0"), the statements inside the braces of the while loop are executed. The Prompt box is displayed and the user enters a number. Now, we loop back to the top and again make the condition test. If they guessed wrong (Guess is still not equal to "3"), the Prompt is displayed again...and again...and again, until the user enters "3." At this point, the conditional expression is evaluated as false, the loop ends, and the Alert box is displayed, ending the function.

The "do while" Loop

The do while loop is similar to the while loop except that you are guaranteed that the statements in the loop will be executed at least one time. Whereas the condition test in the while loop is made at the beginning of the loop (and could initially test false, thereby avoiding the statements in the loop), the condition test in the do while loop is made at the end (after the loop has executed at least one time). Its general format is:

do {
    ...do this...
}
while (conditional expression)

This construction is more appropriate for the number-guessing function since we want the Prompt box to display at least one time. It also saves us from initializing the Guess variable:

function PickEm ( )
{
    do {
        var Guess = prompt ("Guess a number between 1 and 5 to end this loop.", "")
    }
    while (Guess != "3")
    alert ("\nGood guess!")
}

The break Command

Sometimes within for or while loops it may not be necessary to wait for the conditional expression to be satisfied. You might need to jump out of the loop before it is finished. Your script, for example, might be set up to look through a list of 1,000 items to find a match. If, however, it found the match on the first item, it wouldn't be necessary to continue looking through the other 999 items; you would want to break out of the loop and continue your processing of the matched item.

For cases like this, you can use the break command. This statement is placed inside the loop and is executed if some condition, short of the loop ending naturally, is met. In general, the format is:

for (conditional expression1) {
    do this first...
    if (conditional expression2) {
        break }
    do this second...
}
continue with processing

If conditional expression2 is true, the break statement is executed and script control jumps out of the loop--bypassing the do this second... statements--and picks up execution at the continue with processing statements. This construction is illustrated in the following button and script:


<SCRIPT>
function Beer ( )
{
    B1 = " bottles of beer on the wall,\n"
    B2 = " bottles of beer.\n"
    B3 = "Take one down and pass it around...\n"
    B4 = " bottles of beer on the wall.\n\n"
    B5 = "See more beer?"

    for ( i = 99; i >= 1; i -- ) {
        SeeBeer = confirm ("\n" + i + B1 + i + B2 + B3 + (i - 1) + B4 + B5)
        if (SeeBeer == false) {
            break
        }
    }
}
</SCRIPT>

<FORM>
<INPUT TYPE=BUTTON VALUE="Bottles of Beer"
onclick = "Beer ( )" >
</FORM>


The break command can only be used in for and while loops; it cannot be used with do while loops.

The continue Command

Similar but different (as we like to say) to the break command is the continue command. This command permits you to skip back to the start of a for or while loop, rather than skip out of the loop. Its use looks like this:

for (conditional expression1) {
    do this first...
    if (conditional expression2) {
        continue }
    do this second...
}
continue with processing

A condition test, conditional expression2, is made inside the loop. If true, the remaining statements in the loop, do this second..., are skipped and control returns to the top of the loop. This construction is shown with the following button and script, which are variations on the previous application:


<SCRIPT>
function Beer ( )
{
    B1 = " bottles of beer on the wall,\n"
    B2 = " bottles of beer.\n"
    B3 = "Take one down and pass it around...\n"
    B4 = " bottles of beer on the wall.\n\n"

    for ( i = 99; i >= 1; i -- ) {
        SeeBeer = confirm ("\nDo you want to see the beer count?")
        if (SeeBeer == false) {
            continue
        }
        SeeMore = confirm ("\n" + i + B1 + i + B2 + B3 + (i - 1) + B4 + "Continue counting?")
        if (SeeMore == false) {
            break
        }
    }
}
</SCRIPT>

<FORM>
<INPUT TYPE=BUTTON VALUE="Bottles of Beer"
onclick = "Beer ( )" >
</FORM>


The same general processing takes place except now users are asked if they want to see the result of the countdown. If they don't, the continue statement directs control back to the top of the loop, and the countdown continues. Whenever users decide to see the count, it is displayed in a second Confirm box, which also gives users the option of ending the whole sillyness.

Arrays

Program loops are used quite often in building and accessing arrays. An array--called a table in some programming languages--is a sequence of storage locations. Whereas a variable can hold only one piece of data at a time, an array can hold many pieces of data under the same variable name. Each data item in an array is accessed by an index number that refers to the data's location in the array.

The following illustration represents an array named "Greek" that contains five items, each of which is referenced by its index number. That is, the first item in the array is at position Greek[0] and contains the data value "alpha"; the second item in the array is Greek[1] and contains the value "beta"; and so forth. In effect, the variable names for the five items are Greek[0] through Greek[4], a much more convenient way to store and refer to multiple items than having to assign variable names to individual items. Note that the items are numbered starting with 0. This is just a JavaScript pecularity and something you'll need to remember when accessing an array.

Array "Greek"
Greek[0]
Greek[1]
Greek[2]
Greek[3]
Greek[4]

Creating Arrays

Arrays are quite simple to create under the lastest browsers: Navigator 3.0 and Internet Explorer 3.0. You use the statement,

var arrayname = new Array ( )

and JavaScript creates it for you automatically. You just need to supply a name for the array using standard variable naming conventions. To create the array illustrated above, we use the specification:

var Greek = new Array ( )

Now, we need to put data into the array. This is done by assigning a value to each of the positions in the array, remembering to begin with position [0]:

Greek[0] = "alpha"
Greek[1] = "beta"
Greek[2] = "gamma"
Greek[3] = "delta"
Greek[4] = "epsilon"

Accessing Arrays

Any item in an array is accessed by its position. Let's build a simple application to illustrate this. The following button accesses and displays the first five Greek letters:

<SCRIPT>
var Greek = new Array ( )
Greek[0] = "alpha"
Greek[1] = "beta"
Greek[2] = "gamma"
Greek[3] = "delta"
Greek[4] = "epsilon"

function GetGreek ( )
{
    for (i = 0; i <=4; i ++) {
        alert ("\nThe Greek letter at postion " + (i + 1) + " is " + Greek [ i ] ) }
}
</SCRIPT>

<FORM>
<INPUT TYPE=BUTTON VALUE="Greek Letters"
onclick = "GetGreek ( )" >
</FORM>


The script first creates an array named "Greek" and assigns it five values. (Note that the statements are not located inside a function; therefore, the array is "global" and is accessible from any other script associated with the document.)

Next, we define a function named GetGreek ( ), which accesses the array and display its contents. A for loop is used wherein counter variable i is set up to increment from 0 to 4, which will point to the five positions in the array. These five positions, along with their contents, are displayed in an Alert box. Although we must access positions 0 through 4 in the array, we have chosen to display their (alphabetic) positions as 1 through 5. So, we add 1 to i in the Alert box display. Along with this letter position, the letter value is displayed with Greek [ i ], which is a reference to the value stored in the ith position of the array. We then call this function from a button.

Here's another example using a <SELECT> list. Choose the team from the list and click the button to show its corresponding name:


The NL team from is called the

<SCRIPT>
var NameArray = new Array ( )

NameArray [0] = "Reds"
NameArray [1] = "Braves"
NameArray [2] = "Marlins"
NameArray [3] = "Pirates"
NameArray [4] = "Cubs"
NameArray [5] = "Dodgers"
NameArray [6] = "Phillies"
NameArray [7] = "Cardinals"
NameArray [8] = "Astros"
NameArray [9] = "Mets"
</SCRIPT>

<FORM>
The NL team from
<SELECT NAME="TeamList">
<OPTION> Cincinnati
<OPTION> Atlanta
<OPTION> Florida
<OPTION> Pittsburgh
<OPTION> Chicago
<OPTION> Los Angeles
<OPTION> Philadelphia
<OPTION> St. Louis
<OPTION> Houston
<OPTION> New York
</SELECT>
is called the
INPUT TYPE=TEXT NAME="Name" SIZE=15
INPUT TYPE=BUTTON VALUE="Click Me"

onclick = "form.Name.value = NameArray [ form.TeamList.selectedIndex] " >
</FORM>


This application takes advantage of the fact that the index of items in an <OPTION> list (0 - n) matches the index of item in an array (0 - n). First, an array is established containing the names of baseball teams. Next, a <SELECT> form item is created using <OPTION> tags to provide a selectable list of team locations, along with an output area to display the team names when the user clicks the accompanying button.

The event handler in the button is all the processing that needs to be done:

onclick = "form.Name.value = NameArray [ form.TeamList.selectedIndex] "

The postion in the <OPTION> list (0 through 9 in this case) of the select team is given by the selectedIndex property of the form element named "TeamList" (the name of the <SELECT> list). Once we know the position of the selection, we can easily find the corresponding position in the array. The reference form.TeamList.selectedIndex is used as the index to the NameArray to find the corresponding team name, which is assigned to the form field "Name." (We'll formally take up the subject of objects and properties in the next topic.)

Corresponding Arrays

You can use corresponding arrays to perform similar table-lookup functions. This involves creating two parallel arrays. A value is looked up in the first array and its corresponding value accessed from the second array. Below is an applications similar to the previous one. Here, the user types the name of a baseball team and the script returns the franchise location:

Type a NL team name
(e.g., Reds) and tab:

<SCRIPT>
var NameArray = new Array ( )
var TeamArray = new Array ( )
NameArray [0] = "Reds";         TeamArray [0] = "Cincinnati"
NameArray [1] = "Braves";     TeamArray [1] = "Atlanta"
NameArray [2] = "Marlins";     TeamArray [2] = "Florida"
NameArray [3] = "Pirates";      TeamArray [3] = "Pittsburgh"
NameArray [4] = "Cubs";         TeamArray [4] = "Chicago"
NameArray [5] = "Dodgers";   TeamArray [5] = "Los Angeles"
NameArray [6] = "Phillies";     TeamArray [6] = "Philadelphia"
NameArray [7] = "Cardinals";  TeamArray [7] = "St. Louis"
NameArray [8] = "Astros";       TeamArray [8] = "Houston"
NameArray [9] = "Mets";          TeamArray [9] = "New York"

function FindTeam ( form )
{
    for ( i = 0; i <= 9; i ++ ) {
        if ( NameArray [ i ].toLowerCase( ) == form.Name.value.toLowerCase( ) ) {
            form.Name.value = NameArray [ i ]
            form.Team.value = TeamArray [ i ]
            break }
    }
    if ( i > 9 ) {
        form.Team.value = "Not Found" }
}
</SCRIPT>

<FORM>
Type a NL team name<BR>
(e.g., Reds) and tab:<BR>
<INPUT TYPE=TEXT NAME="Name" SIZE=15

    onfocus = "form.Name.value = ''; form.Team.value = '' " >
<INPUT TYPE=TEXT NAME="Team" SIZE=15

    onfocus = "FindTeam (this.form)" >
</FORM>


The script creates the two arrays and initializes them with the names and teams. The statements to fill the arrays with values are placed side-by-side on a line, separated by a semicolon, to make it easier to see the correspondence between the two arrays. The FindTeam ( ) function performs the search to find the franchise location corresponding to a team name.

Input and output appear in the two text fields. The first field (called Name) is where users type a team name; the second field (called Team) is where the script puts the franchise location of the team after finding it in the array. The onfocus event handler of the Name field puts a null value in each of the fields when the user tabs here in order to clear the fields for a new name to be entered. The onfocus handler of the Team field calls the FindTeam ( ) function to search the arrays. (Recall that the onfocus event handler is activated when the user tabs to or clicks inside a field.) When the function is called, the form is passed so the script can have access to the two fields.

The FindTeam (form) function receives the two form fields, the first of which includes a name of a team that the user has entered. The search of the NameArray to find a match occurs within a for loop. The loop is initialized to 0 and incremeted by 1 while indexing through the ten elements of the array. The statement:

if ( NameArray [ i ].toLowerCase( ) == form.Name.value.toLowerCase( ) )

checks each element of the array against the name entered by the user. It also uses the toLowerCase ( ) method to convert both data values to lower-case characters in case the user doesn't type the names exactly as they appear in the array. When there's a match between what the user entered and the array element, the value from the NameArray is placed in the first field of the form and the corresponding value from the TeamArray is placed in the second field of the form. Then the loop is exited. If the for loop gets all the way through the array without finding a match (i = 10), then a "Not Found" message is placed in the Team form field.

Arrays for Older Browsers

The method of creating an array described above works under modern browser. However, if you are writing scripts to work under earlier Netscape and Explorer browsers, you must use a different method. First, you need to create an array object by using the following special function:

<SCRIPT>
function MakeArray ( ArraySize )
{
    this.length = size
    for ( i = 1; i <= ArraySize; i ++ ) {
        this [ i ] = null
    }
    return this
}
</SCRIPT>

Once the function exists, you call it and pass to it the size of array you want to create--size meaning the number of array elements:

var ArrayName = new MakeArray ( ArraySize )

For example,

var MyArray = new MakeArray (100 )

creates an array named MyArray containing 100 elements. Now, you can load and access the array just as described above, with one major exception. An array created in this fashion has its elements numbered beginning with 1, not 0 as in the previous examples. So, you'll need to adjust your processing to account for this change.

Is it a Number?

At the end of the previous page we ran into some difficulties in performing validity checks. In particular, JavaScript does not provide a way to test a (supposedly) numeric form field for non-numeric characters. If a script attempts arithmetic processing on non-numeric data, it simply aborts! Try it:

=

Recall that form fields are always treated as strings. Therefore, you need to convert the string to a number before using it in computations. There are a couple of built-in JavaScript functions that assist in doing this. The eval ( ) function can be used to evaluate a field and return a number, but only if there are numbers in the field. The parseFloat ( ) function can pull the leading numbers out of a mixed-character field, but only if the first character is a number. So, without much help from JavaScript's built-in functions, what we need to do is write our own numeric-check routine. It's not a lot of trouble with for loops. The following script takes care of the problem:


=

<FORM>
<INPUT TYPE=TEXT NAME="Number" SIZE=10 VALUE="garbage">
<INPUT TYPE=BUTTON VALUE="+ 1"
onclick="
    if ( IsNumber ( form.Number.value ) ) { form.Answer.value = eval ( form.Number.value ) + 1 }"
>
= <INPUT TYPE=TEXT NAME="Answer" SIZE=10>
</FORM>

<SCRIPT>
function IsNumber ( Value )
{
    var Numbers = "0123456789.-+"
    var Length = Value.length
    var Counter = 0

    for ( i = 0; i < Length; i ++) {
        for ( j = 0; j < 13; j ++ ) {
            if ( Value.charAt ( i ) == Numbers.charAt ( j ) ) {
                Counter ++
                break }
        }
    }
    if ( Counter == Length ) {
        return true }
    else {
        alert ("\nThat's not a number!")
        return false }
}
</SCRIPT>


The function receives argument Value, which it will check for numeric characters. First off, the script declares variable Numbers and assigns it the decimal characters 0 thru 9, the decimal point (.), the minus sign (-), and the plus sign (+)--all the decimal characters. This string contains the characters against which the passed Value will be checked. Next, it assigns to variable Length the number of characters contained in Value. Each of these characters needs to be checked against the Numbers string, so we need to know how many to check. Third, it establishes a Counter, initialized to zero, for keeping track of how many matches were found. If, at the end of the script, the number of matches equals the Length of the passed Value, then we know there was a match found for each character.

The checking of the Value variable against the Numbers variable takes place one character at a time. Each character of Value is matched against each of the 12 characters of Numbers. So, script-wise, we require a loop within a loop. The outer loop increments through each of the characters in Value; for each of these characters, the inner loop increments through each of the characters in Number.

Two nested for loops are used. The outer loop:

for ( i = 0; i < Length; i ++)

increments variable i from 0 up to the Length of the passed Value. We have to increment from 0 to one less than the length (rather than from 1 to the length) because the characters in a string are numbered starting with 0.

For each of the loops through this for statement, an inner loop:

for ( j = 0; j < 13; j ++ )

increments variable j from 0 to one less than the number of characters in the Numbers string (counting from 0 - 12 rather than 1 - 13). So, while i = 0, j increments from 0 to 12; when i = 1, j increments from 0 to 12; when i = 2, j increments from 0 to 12; and so forth until i reaches the number of characters in Value.

Inside these loops (for each i and each j) an if statement checks for a match between character i of Value and character j of Numbers:

if ( Value.charAt ( i ) == Numbers.charAt ( j ) ) {
    Counter ++
    break }

The .charAt notation simply points to the particular character in the string. If there is a match, the Counter is incremented by 1 and the (inner) loop is terminated (no need to search the entire Numbers string once a match is found). Control then returns to the outer loop to pick up the next character in the Value string and begin checking it against the characters in the Numbers string, continuing until all characters have been checked.

When the loops end, the Counter tells the tale:

if ( Counter == Length ) {
    return true }
else {
    alert ("\nThat's not a number!")
    return false }

If the value of the Counter is the same as the number of characters in variable Value, then a match was found for each character. This is, indeed, a number! So, the script return true. If the Counter value doesn't match the Length of the passed value, at least one character didn't match. The script displays a message to that effect and returns false.

When control returns to the onclick handler that called the function, the returned value is checked:

onclick="if ( IsNumber ( form.Number.value ) ) ...."

This condition test is either true or false depending on which value was returned by the function. If true, then the computation is made:

form.Answer.value = eval ( form.Number.value ) + 1

If false is returned, nothing happens; the entered value was not a decimal number.
 

The for, while, and do while loops-- along with their break and continue inserts--plus the previously described if statements and arrays, should give you powerful tools to face up to any scripting challange involving the logic of iteration and decision making. With these topics we have effectively finished discussion of the structure and command components of the language. We can now turn to a consideration of other JavaScript components that fill in some of the scripting gaps.


Previous Contents Next