Loops

If statements decide whether or not a set of instructions is run at all. Loop statements can decide that, but they also decide how often the same set of instructions is run. There are two types of loops in Javascript:

Each has a special subtype, which I'll get to in their respective sections.

First, however, I want to warn you of something called an infinite loop. An infinite loop is a loop where conditions for repeating the loop are always satisfied, so the loop has no way of ending. The loop can cause the browser to take up all the computer's resources, making the computer run slowly, or if part of the loop's code causes an alert box or the like to show up, make it difficult to close the browser at all. So, with no undue emphasis, beware of infinite loops!

Loop Syntax

Loops have a syntax a little like an if statement: statements go between curly braces, and their conditions are contained in parentheses. However, their specific conditions and structures depend on the loop.

While Loops

A while loop runs an indeterminate number of times. It uses the keyword while, has a condition exactly like that of an if statement, and will run so long as that condition is true. So here is a loop that will run so long as loop is less than 5:

A While Loop
var loop = 0;
while(loop < 5){
}

And what we have is a very nice infinite loop: the value of loop is always 0, and so will always be less than 5. Increasing the value of loop to a number such as 4 will be of no help, since the condition says so long as loop is less than 5, repeat. Eventually, loop will have to be greater than or equal to 5 if this loop is going to end.

Adding Something To A While Loop To Let It End
var loop = 4;
while(loop < 5){
loop += 0.001;
}

The above loop will finally end when the value of loop reaches 5. This, however, will not end at all:

Another Infinite While Loop
var loop = 0;
while(loop != 5){
loop += 0.003;
}

Why not? Look at these values of loop over 4.99:

The loop runs so long as loop does not equal 5, but the value 5 is skipped over, and of course, the more the loop runs, the further away that value gets from 5. If the condition was (loop < 5), however, the value 5.001 would render the condition false, and the loop would end.

So let's create a while loop that will actually do something:

A While Loop That Adds To A String
var loop = 0;
var text = "";
while(loop < 5){
text += "loop equals " + loop + ". ";
loop++;
}
document.getElementById("JS").firstChild.data = text;
The output of a while loop

Do-While Loops

The main difference between a while loop and a do-while loop is the latter runs at least once. In other words, if the condition for either type of loop is false from the very beginning, a while loop will not run at all, and a do-while loop will run exactly once.

The syntax here is a little different than most loops, since the condition comes at the end. The following code runs a loop so long as foo is less than 5, showing the difference between them.

Do while loops require the use of the keyword do.

Comparison Of While & Do-While Loops
Note: Their Conditions Are False Before Either Loop Begins
While Loop
var loop = 6;
var text = "";
while(loop < 5){
text += "loop equals " + loop + ". ";
loop++;
}
document.getElementById("JS").firstChild.data = text;
Do While Loop
var loop = 6;
var text = "";
do{
text += "loop equals " + loop + ". ";
loop++;
} while (loop < 5);
document.getElementById("JS").firstChild.data = text;
Results of a While Loop
The output of a while loop
Results of a Do-While Loop
The output of a do-while loop

So which is the best to use? Here's a rule of thumb: If you can save a few lines of coding by using a do-while loop, by all means go for it unless it should be possible for the loop not to run at all.

Nodes and While Loops

This example actually comes from personal experience. I had a script for multiple pages, and I needed the text from the h1 element from each page for my script. However, sometimes the text was in a span element, sometimes it wasn't.

To make sure I got the text from a text node, rather than an element node (which would create an error and cause the script to halt), the following do-while loop came in handy:

Using A Do-While Loop To Dig Through Nodes
var h1_text = document.getElementsByTagName("h1")[0];
do{
h1_text = h1_text.firstChild;
} while (h1_text.nodeType != 3);
h1_text = h1_text.data;

Basically, the loop above takes the node of the first h1 element in the page, assigning a reference to that node to the variable h1_text. Then it assigns a reference to that node's first child node to h1_text (remember how I said you could adjust a variable's value? This is doing it with DOM nodes.) If that doesn't result in a text node (which has a node type of 3), the loop gets the next first child node until it gets a text node. If there's no actual text node in the h1 element, that won't make this an infinite loop. What will happen is the browser will encounter an error (rather drastically termed a fatal error) and stop running the script altogether.

For Loops

A for loop is set to run a specific number of times, which is set up in the condition. The condition is actually a little more complex than what's used in a while loop. A while loop simply has a condition that must prove true. A for loop declares its start, its end, and how it gets there all in the loop condition.

Below is a comparison of a for loop to a while loop:

Comparing While And For Loops
A While Loop
var loop = 0;
var text = "";
while(loop < 5){
text += "loop equals " + loop + ". ";
loop++;
}
document.getElementById("JS").firstChild.data = text;
A For Loop
var text = "";
for(var loop = 0; loop < 5; loop++){
text += "loop equals " + loop + ". ";
}
document.getElementById("JS").firstChild.data = text;

In order, the condition for the for loop declares:

  1. the loop start,
  2. loop finish,
  3. and how the loop reaches the finish.

I've said earlier that semi-colons are optional. In the condition of a for loop, they're not—they divide the parts of the condition. The result for this loop is exactly the same as the while loop:

The output of a for loop

For Loops And Arrays

One of the most common uses of for loops is going through the contents of an array in sequence—be it an array of numbers, strings or a list of node references. Remember when I said that length got the number of elements in an array? That comes in really useful in a for loop. To display this, I've created an array where each element contains its index in words (remember the first element in an array has an index of 0). The loop, which will start at 0 and end at 1 less than the array's length, runs code that adds to the string in text. When the loop is done, the script assigns the result to an element's text node.

A For Loop Going Through An Array
var numbers = new Array("Zero", "One", "Two", "Three", "Four");
var text = "";
for(var loop = 0; loop < numbers.length; loop++){
text += "loop equals " + numbers[loop] + ". ";
}
document.getElementById("JS").firstChild.data = text;
For Loop With Array

For Loops and Node Lists

Like arrays, for loops are also used a lot with node lists. Below, I am creating a script that will show the text of the first paragraph of the page created in Your First Webpage in an alert box. This is complicated because, as I said The Document object Model, text nodes are split up by element nodes. Therefore, we have to go through each text and element node in turn and extract the text.

  1. Create a variable that contains a node list of the first p element's child node.
  2. Create a variable to store the string.
  3. Create a loop to go through each node in the list.
  4. In that loop, we need to differentiate between child text node and child element node.
  5. Build the string of text via concatenation.
  6. Show the results in an alert box.
Extracting Text From A Paragraph
var p_child = document.getElementById("p_1").childNodes;
var p_text = "";
for(var loop = 0; loop < p_child.length; loop++){
if(p_child[loop].nodeType == 3){
p_text += p_child[loop].data;
} else {
p_text += p_child[loop].firstChild.data;
}
}
alert(p_text);
Using The Above With If/Else Shorthand
var p_child = document.getElementById("p_1").childNodes;
var p_text = "";
for(var loop = 0; loop < p_child.length; loop++){
p_text += (p_child[loop].nodeType == 3)?(p_child[loop].data):(p_child[loop].firstChild.data);
}
alert(p_text);
The extracted text

For-In Loops

For-In loops are specifically for arrays (and objects, which we'll get to later). It starts out with the keyword for, like any other for loop. However, its condition is radically different: a variable to work as a counter, followed by the keyword in, followed by the array or object whose elements or properties you want to access. Let's take, for example, the loop I demonstrated above in the array example:

Comparing For Loops And For-In Loops
As A For Loop
var numbers = new Array("Zero", "One", "Two", "Three", "Four");
var text = "";
for(var loop = 0; loop < numbers.length; loop++){
text += "loop equals " + numbers[loop] + ". ";
}
document.getElementById("JS").firstChild.data = text;
As A For-In Loop
var numbers = new Array("Zero", "One", "Two", "Three", "Four");
for(loop in numbers){
text += "loop equals " + numbers[loop] + ". ";
}
document.getElementById("JS").firstChild.data = text;

The results would be the same:

For Loop With Array

Just a note: node lists will not work with for-in loops because not only does such a loop return the node references but also methods and properties that are not nodes; these extras are vital and inherent parts of a node list, but they will show up in a for-in loop, which can cause such a script to crash.

Nesting Loops

Much like if statements, you can nest loops. This is often used when you have arrays of arrays, having an outer loop to go through the containing array, and an inner loop going through each of the contained arrays in turn. Let me show you what I mean. Below is an array of arrays. No, not all the inner arrays are the same length. I did that deliberately to show you that their length doesn't matter.

Nested Array
var my_array = [
["0-0", "0-1", "0-2", "0-3", "0-4"],
["1-0", "1-1", "1-2"],
["2-0", "2-1", "2-2", "2-3", "2-4", "2-5"],
["3-0", "3-1", "3-2", "3-3", "3-4"]
]

To go through each element of my_array, we need a for loop. In this context, this will go through each element of the main array, each of which contains a sub-array.

The Outer Loop
for(var loop = 0; loop < my_array.length; loop++){
}

To go through each element of each sub-array, we need a second loop nested within the first one. Because I'm already using the variable loop, I have to use a variable with another name. I'll using loop2. Remember, every single element in my_array is an array itself, which is why I can use the property length on those elements—and because the length is recalculated for each array, their differing lengths won't be a problem.

Nested Loops
for(var loop = 0; loop < my_array.length; loop++){
for(var loop2 = 0; loop2 < my_array[loop].length; loop2++){
}
}

Putting all this together, adding a variable for text, updating that variable through the two loops, and using it for something, we get the following:

Nested Loops
var my_array = [
["0-0", "0-1", "0-2", "0-3", "0-4"],
["1-0", "1-1", "1-2"],
["2-0", "2-1", "2-2", "2-3", "2-4", "2-5"],
["3-0", "3-1", "3-2", "3-3", "3-4"]
]
var text = "";
for(var loop = 0; loop < my_array.length; loop++){
text += "LOOP " + loop + ": ";
for(var loop2 = 0; loop2 < my_array[loop].length; loop2++){
text += my_array[loop][loop2] + " ";
}
text += ". ";
}
document.getElementById("JS").firstChild.data = text;

And that gives us the following result:

The output of nested loops

Fixing Examples With Loops

In JavaScript Text, there were a few occasions where I omitted several lines of code because they were repetitive, long, and repetitive. Here's one of the examples:

Using the split Method
(Original Code)
// Create String
var string = "The text string we are working with.";
 
// Create array of arrays. Each array is our string split in a different fashion.
var split_strings = [
string.split(" "), // Split on the spaces.
string.split(" ", 4), // Split on the spaces, but has a limit of 4.
string.split(""), // Split into individual characters
string.split("", 2), // Split into individual characters, but has a limit of 2
string.split("e"), // Split on the letter "e"
string.split("e", 3) // Split on the letter "e", but has a limit of 3.
];
 
// Write the strings.
var trs = document.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
trs[0].getElementsByTagName("td")[1].firstChild.data = split_strings[0].length;
trs[0].getElementsByTagName("td")[2].firstChild.data = split_strings[0][0];
trs[0].getElementsByTagName("td")[3].firstChild.data = split_strings[0][1];
trs[0].getElementsByTagName("td")[4].firstChild.data = split_strings[0][2];
trs[0].getElementsByTagName("td")[5].firstChild.data = split_strings[0][3];
trs[0].getElementsByTagName("td")[6].firstChild.data = split_strings[0][4];
Author's Note: The above six lines repeat five more times, with 36 such lines total. Both the index of trs and the first index of split_strings increase by 1 each time. For the sake of space, I omitted the rest of the lines from this example.
document.getElementById("OStr").firstChild.data = string;

Repetitive lines like that are just what loops were made for. As you can see, these have two sets of indices, which means we'll have to create a nested loop. First, an outer one to take care of the index of trs and the primary index of split_strings. Since the length of both arrays are identical, I can use the length of either:

Using the split Method
(Creating A Loop To Handle Repetitive Lines)
var trs = document.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
for(var loop = 0; loop < split_strings.length; loop++){
trs[loop].getElementsByTagName("td")[1].firstChild.data = split_strings[loop].length;
trs[loop].getElementsByTagName("td")[2].firstChild.data = split_strings[loop][0];
trs[loop].getElementsByTagName("td")[3].firstChild.data = split_strings[loop][1];
trs[loop].getElementsByTagName("td")[4].firstChild.data = split_strings[loop][2];
trs[loop].getElementsByTagName("td")[5].firstChild.data = split_strings[loop][3];
trs[loop].getElementsByTagName("td")[6].firstChild.data = split_strings[loop][4];
}
document.getElementById("OStr").firstChild.data = string;

That might add a couple lines to my code, but it now omits 30 others.

The inner loop might seem a little complicated because the two remaining indexes are different, and one of the lines refers to a property, not to an array element. But remember: an array index can also include an equation. First we set aside the non-repetitive line. We can also save ourselves some typing by using the outer loop to reassign a list of td elements to a variable (let's call it tds). Then we nest the other lines in an inner loop:

Using the split Method
(Creating An Inner Loop To Handle Repetitive Lines Within The Outer Loop)
var trs = document.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
for(var loop = 0; loop < split_strings.length; loop++){
var tds = trs[loop].getElementsByTagName("td");
tds[1].firstChild.data = split_strings[loop].length;
for(var loop2 = 2; loop2 < tds.length; loop2++){
tds[loop2].firstChild.data = split_strings[loop][loop2 - 1];
}
}
document.getElementById("OStr").firstChild.data = string;

The final script reads as:

Using the split Method
(The Complete Script)
// Create String
var string = "The text string we are working with.";
 
// Create array of arrays. Each array is our string split in a different fashion.
var split_strings = [
string.split(" "), // Split on the spaces.
string.split(" ", 4), // Split on the spaces, but has a limit of 4.
string.split(""), // Split into individual characters
string.split("", 2), // Split into individual characters, but has a limit of 2
string.split("e"), // Split on the letter "e"
string.split("e", 3) // Split on the letter "e", but has a limit of 3.
];
 
// Write the strings.
var trs = document.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
for(var loop = 0; loop < split_strings.length; loop++){
var tds = trs[loop].getElementsByTagName("td");
tds[1].firstChild.data = split_strings[loop].length;
for(var loop2 = 2; loop2 < tds.length; loop2++){
tds[loop2].firstChild.data = split_strings[loop][loop2 - 1];
}
}
document.getElementById("OStr").firstChild.data = string;

The results are exactly the same. The script, on the other hand, is 29 lines shorter. Similarily, the example of the indexOf, lastIndexOf, and search methods could easily be reduced by using nested loops:

The code has been reduced by 13 lines.

Don't think that this kind of shortcut is sloppy coding or might cause more errors. First, it is tedious to have to type something over and over and over and over and over and over and oer again. Second, repetitive typing makes it more likely for you to make mistakes (see previous sentence).