Webpages and stylesheets are rendered from top to bottom. Scripts (and most other programs) are not. Since scripting languages are programming languages, they can decide whether or not to run some code, repeat the same set of instructions, reference different parts of themselves, and even reference each other, if you've got more than one script.
The decisions are done by if statements and switch statements, the repetition done by loops, and referencing is done using procedures. I'll get to the last two later.
An if statement contains code that will run only if a condition is true, if/else statements have one set of instructions for a condition proving true, a second for the condition proving false, and if/else if/else have several conditions to be checked in order.
There are a few special characters to deal with when working with if statements.
The following are some comparison operators. Some of them work with numbers only, but a few can work with strings as well.
not. In the last chapter, I mentioned the
true
keyword. Therefore, !true
would mean not true, which is the same as
false
.Is equal to. Note that there are two equal signs; this keeps the equality operator from being confused with
=, which assigns values, and may be used in this context. This works on strings as well as numbers.
Is exactly equal to. In this case, if I'm comparing a variable to the number five, not only must the variable contain the value
5, but the value must be a number. If it's a string, this will prove false.
Is not equal to. Note the use of
!. This works on strings as well as numbers.
Is less than. The second term means
Is less than or equal to.
Is greater than. The second term means
Is geater than or equal to.
The following values that will prove automatically false:
false
undefined
null
This is a good thing: false
is a boolean value (the only other possible value is true
), an empty string can't have any matching, replacements, or any other such string manipulation done with it, and undefined
and null
both mean there's nothing here
. The false value most likely to cause trouble is 0
. That's where ===
comes in handy, since it will check the value as a number, instead of a potential false
value.
The simplest type of decision is the if statement, which has code that is executed if the condition proves true. Whether or not it is run, the program goes on its merry way to the rest of itself.
For example, let's take the following code:
var
bool = true;
var
foo = "False"
;if
(bool){"True"
;document
.getElementById
("JS"
).firstChild
.data
= foo;In the above code, the variable bool is set to true
. Note that I don't have quotation marks around true
in the code. This is because true
is not a string, it is a boolean value, and remember I said that a boolean value is always either true
or false
.
Okay, now that that's out of the way, let's move on.
The variable foo is declared and contains the word False
. Then there is an if statement with a condition that says if the variable bool holds a value that is considered true, execute this if statement's code.
After that, write the resulting text to the text node with a parent element node with an ID of JS
.
The variable bool does indeed hold the value true
, so the code within the if statement is executed. The code says, Change the value of foo to the word
And the value is indeed changed:True
.
But say bool was false?
var
bool = false
;var
foo = "False"
;if
(bool){"True"
;In this case, the condition is false, so the if statement's code is completely skipped, and the value of foo remains unchanged:
An if/else statement allows for another set of instructions to be run if the if statement's condition is false. For example, let's set up an if statement that states whether or not foo equals 5
.
var
answer; // No need for a value yetif
(foo == 5){ // Note the comparison operator!"Foo equals 5"
;else
{"Foo does not equal 5"
;document
.getElementById
("JS"
).firstChild
.data
= answer;You don't have to have else right where it is; you can have it on its own line, but I did admit that this book is rife with my own coding habits.
If foo does equal 5, answer will be given the value Foo equals 5
. But if foo was any other number, then the else part would be run instead, and answer would be given the value Foo does not equal 5
. This is demonstrated below:
There is a shorthand way of writing if/else statements, and it's common to many coding languages. It is:
Rewriting the above code using this shorthand gives you:
var
answer = (foo == 5)?"Foo equals 5"
:"Foo does not equal 5"
;document
.getElementById
("JS"
).firstChild
.data
= answer;From seven lines of code to only two! Below, I cut out yet another line:
document
.getElementById
("JS"
).firstChild
.data
= (foo == 5)?"Foo equals 5"
:"Foo does not equal 5"
;Do note, however, this only works with if/else statements!
Because of the way this statement is constructed, it can be used in more places than the usual if/else statement. Below are examples of these places.
document
.getElementById
("JS"
).firstChild
.data
= "Foo "
+ ((foo == 5)?"equals"
:"does not equal"
) + " 5"
;var
equality = Array
('equals'
, 'does not equal'
);document
.getElementById
("JS"
).firstChild
.data
= "Foo "
+ equality[(foo == 5)?0:1] + " 5"
;I have used both usages from time to time.
The shorthand if statement's strength is its strictly-defined usage. The shorthand if statement's weakness is its strictly-defined usage. In short, it can only pass one value or another in a single context, whether it is assigning a value to a variable, or selecting an array element, or choosing what to concatenate to a string, or something else. It cannot choose between variables to assign values to, nor can it choose which array to get an index from, nor can it choose which string to concatenate to. If that's what you want to do, use a full if statement.
The else if
pair of keywords allows you to add more options to an if/else statement. You can only have one if statement and one else statement, but infinite else if statements. What it means is, if the preceding conditions are not true, what about this one?
Below is the code for a script that checks to see if foo
is higher or lower than 5
var
answer = "Foo is "
; // The beginning two words will be identical in every case, so I may as well put it here.if
(foo < 5){"less than "
;else if
(foo > 5){"greater than "
;else
{"equal to "
;"5"
; // The last number is identical in every case, so I may as well put it here.The above code first checks to see if foo is less than 5. If foo equals 3
, then yes, it is less than 5. If it was greater than or equal to 5, then the first condition would be false.
The code then checks to see if foo is greater than 5. If foo was equal to 3
, the first condition would have been satisfied, and the rest of the instructions ignored. However, if foo was equal to 6, then the second condition would be satisfied.
If foo is neither greater nor less than 5, then logic dictates that it would be exactly equal to 5, and thus the code of the else portion of this statement.
You can actually nest if statements, especially when the conditions on the inner if statement depend on those of the outer if statement. For example with our code, let's imagine that, instead of a numerical value, foo might contain the string Something else
instead. If not, then we can check its numerical value. First, we check to see if the string's value can be converted into a number at all. If it can't be converted to a number, then the function isNaN
will return true
.
var
answer = "Foo is "
; // The beginning two words will be identical in every case, so I may as well put it here.if
(isNaN
(foo)){"a string of text."
;else
{If isNaN
returns true
(in other words, if foo is not a number), then Foo is a string of text
is the script's final answer. If isNaN
returns false
(literally, if foo is not not a number), then the else statement comes into play:
var
answer = "Foo is "
; // The beginning two words will be identical in every case, so I may as well put it here.if
(isNaN
(foo)){"a string of text."
;else
{if
(foo < 5){"less than "
;else if
(foo > 5){"greater than "
;else
{"equal to "
;"5"
; // The last number is identical in every numerical case, so I may as well put it here.The results are:
With the methods I explained in the chapter on text, you can see how easily these methods can be converted into conditions for if statements. Below is a group of conditions that take advantage of indexOf
, lastIndexOf
, search
, and match
.
The first three use a simple mathematical comparison: any returned value greater than -1 means that the substring was found, and thus this returns true
.
if
(string.indexOf
(substr) > -1){...}if
(string.lastIndexOf
(substr) > -1){...}if
(string.search
(substr) > -1){...}The match
method, however, returns null
if it doesn't find a match and, as I said at the beginning of the chapter, null
is always considered to be false. That makes this method a bit simpler.
if
(string.match
(substr)){...}There are times when more than one condition decides whether or not code is run. There are two variants of this: either a) all conditions must be met, or b) at least one condition must be met. Variant a
can be emulated with nested if statements, while variant b
requires at least three if statements in succession. In the examples below, foo must equal five
if a statement is to prove true, while bar must equal 5
.
if
(foo == "five"
){if
(bar == 5){If any coding goes inside the outer if statement but outside the inner statement, this is what you would use. But if all your coding is inside the inner if statement, the way to shorten it us to use the and
operator: &&
. Using this operator, you can put both conditions into a single, larger condition, but you must write both conditions so they can stand on their own.
if
(foo == "five"
&& bar == 5){This reduces the coding by two lines, and makes the statement similar to follow. You can use this with as many conditions as you like.
It gets somewhat more complex when you want either condition to prove true.
var
boolean = false
;if
(foo == "five"
){boolean = true
;}if
(bar == 5){boolean = true
;}if
(boolean){A slightly shorter way to do this would be assigning a condition to a variable. Yes, you can do that, and the result will be a boolean value.
var
boolean = (foo == "five"
);if
(!boolean){boolean = (bar == 5);}if
(boolean){If there's no other pertinent coding, this can be shrunk using the or operator: ||
.
if
(foo == "five"
|| bar == 5){I mentioned back in Math that operations inside parentheses are always done first, and the results are applied to operations outside the parentheses. Conditions are no different. A limitation of the or operator is that it cannot distinguish between only one or more than one condition to be true. If you wanted a condition that would prove true if foo was five
or bar was 5
, but not both, you'd have to get a little more complex and use two and operators, an or operator, and a total of four conditions (since we're working with two variables).
if
("five"
&& bar != 5) If "foo" equals "five" and bar does NOT equal "5""five"
&& bar == 5) If "foo" does NOT equal "five" and bar equals "5"As they're in parentheses, the two statements with the and operators are processed first. Because of the way they're set up, if foo equals five
and bar equals 5
, then in both conditions, something will prove false and—because of the and statements—both subconditions will prove false, causing the condition as a whole to prove false. The same is true if neither foo equals five
or bar equals 5
.
But if only foo equals five
or bar equals 5
(meaning the other variable equals something else, say bar equals 42
or foo equals Mr. Billion
), then one of those subconditions will prove true: either foo will equal five
and bar will not equal 5
or vice versa. Because of the or operator, the condition as a whole will prove true.
The order of subconditions is important: aside from what are in parentheses, subconditions are processed in the order they occur. This comes in handy, and I'll show you why.
In Dynamic Behavior And Scripting, I mentioned that the src
attribute, used by the script
element to refer to an external script file, would cause the bowser not to process anything in the script
element itself. I also said you could use this to your advantage.
I have used this little fact to place flags
, or little bits of text, to determine whether or not I wanted a section of script to be run. Say I have a script that looks for the flag RandomImage
in the script
element that refers to the external script file.
var
scripts = document
.getElementsByTagName
('script'
);var
this_script = scripts[(scripts.length
- 1)];if
(this_script.firstChild
.data
.match
("RandomImage"
){The above code will work fine—so long as the script
element has a first child node. It is entirely possible that the script element would look like this:
script
type
="text/javascript"
src
="./script.js"
></script
>The script will encounter an error because there is no firstChild node to extract data from and match. The problem can be avoided by first checking to see if there is such a node at all:
var
scripts = document
.getElementsByTagName
('script'
);var
this_script = scripts[(scripts.length
- 1)];if
(this_script.firstChild
&& this_script.firstChild
.data
.match
("RandomImage"
){Because it uses the &&
operator, if the first condition proves false, the script won't bother with the rest of it; in this case, that means if this_script.firstChild
does not exist, the script will not try to seek the RandomImage
flag. If the two subconditions were reversed, the script would attempt to make the match, then check to see if the script
element might have a child node. Obviously, this is no better than not doing a child node check at all.
As explained in Regular Expressions, the test
returns true
or false
, making them ideal for use in if statements. I also mentioned in the same chapter that false matches could occur. With this knowledge, I am going to show how to filter out possible false matches. The first regex I'm going to use is intended to match a valid Canadian phone numbers. The other regexes are intended to filter out possible errors by matching those.
0Or
1
if
(/((1-)?[2-9][0-9]{2}-)?[2-9][0-9]{2}-[0-9]{4}/
.test
(phone_number)) &&// The "!", the grouping with parentheses, and the "||" used below mean
that ALL the following conditions must prove FALSE for the condition as a whole to prove TRUE.
/[01][0-9]{2}-[0-9]{3}-/
.test
(phone_number) || //The first expression that would match an invalid phone number.
/([0-9]{3}-){3}/
.test
(phone_number) || //The other expression that would match an invalid phone number.
In this way, I exclude anything I don't want to match.
Confirm popups are sort of like alert boxes, but they allow you to make a choice. Clicking Okay
returns true
, while clicking Cancel
will return false. Below, I've created a short demonstration of the confirm box.
if
(confirm
("Do you want to click 'OK'?"
)){alert
("You clicked 'OK'."
);else
{alert
("You clicked 'Cancel'."
);A switch statement works a bit like an if/else if/else statement, but it looks for an exact match rather than a broad generalization. For example, you can't use a switch statement to see if foo is higher or lower than 5, but you can use a switch statement to see if a number is 4, 5, or 6.
For example, say you've written a script, and part of it needs to see what type of node foo is. An if/else if/else statement could work, but this suits a switch statement as well: there is a limited list of 12 node types—a list you can limit further because most are never used in HTML-oriented scripting anyway—and most of those aren't all that common in XHTML scripting either.
The syntax of a switch statement is a bit complex. First, you have to declare a switch statement with the keyword switch
. The keyword is followed by the variable name in parentheses, and everything it works with after that is in curly brackets. So here is the code we set up, along with the variables we'll use:
var
node = document.getElementById("JS"
);var
foo = node.nodeType
;var
text;switch
(foo){I do have the alternative, of course, to write the above code like this:
var
node = document.getElementById("JS"
);var
text;switch
(node.nodeType
){The above will work perfectly well.
Conditions here are known as cases, and they are shown by the keyword case
. The keyword case
is followed by the value to be matched, which is then followed by a colon. The node types we'll be looking for are numbers 1, 3, and 9 (element, text, and document, respectively).
var
node = document.getElementById("JS"
);var
foo = node.nodeType
;var
text;switch
(foo){case
1:case
3:case
9:Following these is the code you want each case to execute:
var
node = document
.getElementById
("JS"
);var
foo = node.nodeType
;var
text;switch
(foo){case
1:"Element node"
;case
3:"Text node"
;case
9:"Document node"
;So lets run this:
Something doesn't make sense; node clearly refers to an element node, not a document node. The problem is, when a case is matched, the rest of the code is run as well. So, when
is matched, the variable text is assigned the string case
1Element node
—then Text node
and finally Document node
.
To stop the rest of the coding from executing, you need the break
keyword, which means leave this set of instructions; you're done.
The last keyword in a switch statement is default
, which means that if no case is matched, this is what runs. It doesn't need the keyword break
because it's a last resort anyway. Adding that in will give us a complete switch statement.
var
node = document
.getElementById
("JS"
);var
foo = node.nodeType
;var
text;switch
(foo){case
1:"Element node"
;break
;case
3:"Text node"
;break
;case
9:"Document node"
;break
;default
:"A different node"
;document
.getElementById
("JS"
).firstChild
.data
= text;Because foo refers to an element node, the result is:
You could, of course, rewrite the entire thing like this:
var
node = document
.getElementById
("JS"
);var
foo = node.nodeType
;var
text;if
(foo == 1){"Element node"
;else if
(foo == 3){"Text node"
;else if
(foo == 9){"Document node"
;else
{"A different node"
;document
.getElementById
("JS"
).firstChild
.data
= text;Some prefer switch statements, others swear by if/else if/else statements, and I just pity the foo who doesn't know there's a choice.
Like if statements, switch statements can work with strings as well, with each case being followed by a string you want to be matched. In the example below, I match the name given to each type of element (which are exactly what I wrote them here as), and return a description from that.
var
element_name = "p"
var
node = document
.getElementsByTagName
(element_name)[0].nodeName
;var
text = " "
;switch
(node){case
"HTML"
:"<html> Element"
break
;case
"HEAD"
:"<head> Element"
;break
;case
"BODY"
:"<body> Element"
;break
;case
"P"
:"<p> Element"
;break
;case
"META"
:"<meta> Element"
;break
;case
"TITLE"
:"<title> Element"
;break
;case
"SCRIPT"
:"<script> Element"
;break
;default
:"A different Element"
;document
.getElementById
("JS"
).firstChild
.data
= text;This, of course, would return <p> Element
.
You may wonder why all the element names to be matched are in capital letters. Remember back in Your First Webpage, I mentioned that in HTML, case didn't matter when it came to element names? Here's an exception: so far as the HTML DOM is concerned, tag names are always in capitals. In the XHTML DOM, they're always lower-case.