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!
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.
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:
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.
var
loop = 4;while
(loop < 5){The above loop will finally end when the value of loop reaches 5. This, however, will not end at all:
var
loop = 0;while
(loop != 5){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:
var
loop = 0;var
text = ""
;while
(loop < 5){"loop equals "
+ loop + ". "
;document
.getElementById
("JS"
).firstChild
.data
= text;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
.
var
loop = 6;var
text = ""
;while
(loop < 5){"loop equals "
+ loop + ". "
;document
.getElementById
("JS"
).firstChild
.data
= text;var
loop = 6;var
text = ""
;do
{"loop equals "
+ loop + ". "
;while
(loop < 5);document
.getElementById
("JS"
).firstChild
.data
= text;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.
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:
DigThrough Nodes
var
h1_text = document
.getElementsByTagName
("h1"
)[0];do
{firstChild
;while
(h1_text.nodeType
!= 3);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.
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:
var
loop = 0;var
text = ""
;while
(loop < 5){"loop equals "
+ loop + ". "
;document
.getElementById
("JS"
).firstChild
.data
= text;var
text = ""
;for
(var
loop = 0; loop < 5; loop++){"loop equals "
+ loop + ". "
;document
.getElementById
("JS"
).firstChild
.data
= text;In order, the condition for the for loop declares:
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:
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.
var
numbers = new
Array
("Zero"
, "One"
, "Two"
, "Three"
, "Four"
);var
text = ""
;for
(var
loop = 0; loop < numbers.length
; loop++){"loop equals "
+ numbers[loop] + ". "
;document
.getElementById
("JS"
).firstChild
.data
= text;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.
p
element's child node.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){data
;else
{firstChild
.data
;alert
(p_text);var
p_child = document
.getElementById
("p_1"
).childNodes
;var
p_text = ""
;for
(var
loop = 0; loop < p_child.length
; loop++){nodeType
== 3)?(p_child[loop].data
):(p_child[loop].firstChild
.data
);alert
(p_text);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:
var
numbers = new
Array
("Zero"
, "One"
, "Two"
, "Three"
, "Four"
);var
text = ""
;for
(var
loop = 0; loop < numbers.length
; loop++){"loop equals "
+ numbers[loop] + ". "
;document
.getElementById
("JS"
).firstChild
.data
= text;var
numbers = new
Array
("Zero"
, "One"
, "Two"
, "Three"
, "Four"
);for
(loop in
numbers){"loop equals "
+ numbers[loop] + ". "
;document
.getElementById
("JS"
).firstChild
.data
= text;The results would be the same:
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.
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.
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.
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.
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:
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++){"LOOP "
+ loop + ": "
;for
(var
loop2 = 0; loop2 < my_array[loop].length
; loop2++){" "
;". "
;document
.getElementById
("JS"
).firstChild
.data
= text;And that gives us the following result:
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:
split
Methodvar
string = "The text string we are working with."
;var
split_strings = [split
(" "
), // Split on the spaces.split
(" "
, 4), // Split on the spaces, but has a limit of 4.split
(""
), // Split into individual characterssplit
(""
, 2), // Split into individual characters, but has a limit of 2split
("e"
), // Split on the letter "e"split
("e"
, 3) // Split on the letter "e", but has a limit of 3.var
trs = document
.getElementsByTagName
("tbody"
)[0].getElementsByTagName
("tr"
);getElementsByTagName
("td"
)[1].firstChild
.data
= split_strings[0].length
;getElementsByTagName
("td"
)[2].firstChild
.data
= split_strings[0][0];getElementsByTagName
("td"
)[3].firstChild
.data
= split_strings[0][1];getElementsByTagName
("td"
)[4].firstChild
.data
= split_strings[0][2];getElementsByTagName
("td"
)[5].firstChild
.data
= split_strings[0][3];getElementsByTagName
("td"
)[6].firstChild
.data
= split_strings[0][4];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:
split
Methodvar
trs = document
.getElementsByTagName
("tbody"
)[0].getElementsByTagName
("tr"
);for
(var
loop = 0; loop < split_strings.length
; loop++){getElementsByTagName
("td"
)[1].firstChild
.data
= split_strings[loop].length
;getElementsByTagName
("td"
)[2].firstChild
.data
= split_strings[loop][0];getElementsByTagName
("td"
)[3].firstChild
.data
= split_strings[loop][1];getElementsByTagName
("td"
)[4].firstChild
.data
= split_strings[loop][2];getElementsByTagName
("td"
)[5].firstChild
.data
= split_strings[loop][3];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:
split
Methodvar
trs = document
.getElementsByTagName
("tbody"
)[0].getElementsByTagName
("tr"
);for
(var
loop = 0; loop < split_strings.length
; loop++){var
tds = trs[loop].getElementsByTagName
("td"
);firstChild
.data
= split_strings[loop].length
;for
(var
loop2 = 2; loop2 < tds.length
; loop2++){firstChild
.data
= split_strings[loop][loop2 - 1];document
.getElementById
("OStr"
).firstChild
.data
= string;The final script reads as:
split
Methodvar
string = "The text string we are working with."
;var
split_strings = [split
(" "
), // Split on the spaces.split
(" "
, 4), // Split on the spaces, but has a limit of 4.split
(""
), // Split into individual characterssplit
(""
, 2), // Split into individual characters, but has a limit of 2split
("e"
), // Split on the letter "e"split
("e"
, 3) // Split on the letter "e", but has a limit of 3.var
trs = document
.getElementsByTagName
("tbody"
)[0].getElementsByTagName
("tr"
);for
(var
loop = 0; loop < split_strings.length
; loop++){var
tds = trs[loop].getElementsByTagName
("td"
);firstChild
.data
= split_strings[loop].length
;for
(var
loop2 = 2; loop2 < tds.length
; 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:
var
string = "If two values are shown between parentheses, the second is not used in the search() method"
;var
indices = [indexOf
("e"
), string.lastIndexOf
("e"
), string.search
("e"
)],indexOf
("e"
, 20), string.lastIndexOf
("e"
, 20), string.search
("e"
)],indexOf
(","
), string.lastIndexOf
(","
), string.search
(","
)],indexOf
(","
, 20), string.lastIndexOf
(","
, 20), string.search
(","
)],indexOf
("search"
), string.lastIndexOf
("search"
), string.search
("search"
)],indexOf
("z"
), string.lastIndexOf
("z"
), string.search
("z"
)]var
trs = document
.getElementsByTagName
("tbody"
)[0].getElementsByTagName
("tr"
);for
(var
loop = 0; loop < indices.length
; loop++){for
(var
loop2 = 0; loop2 < indices[loop].length
; loop2++){getElementsByTagName
("td"
)[loop2 + 1].firstChild
.data
= indices[loop][loop2];document
.getElementById
("JS"
).firstChild
.data
= string;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).