JS Control Structures

The control structures within Javascript allow the program flow to change within a unit of code or function. These statements can determine whether or not given statements are executed, as well as repeated execution of a block of code.

With the exception of the switch control structure, all control structures can operate either on a statement or a block of code enclosed with braces ({ and }). The same structures utilize booleans to determine whether or not a block gets executed, where any defined variable that is neither zero or an empty string is treated as true.

The 'if' statement
if( myVariable == 2 ) { myVariable = 1; } else { myVariable = 0; }

If myVariable had been 2 it would now be 1. If it had been anything other than 2 it would now be 0.

'If' statements can also test for the occurence of a child object of an object that may not exist. For example, some browsers provide document.body.style while some older browsers do not even provide document.body. In these browsers, writing 'if( document.body.style )' would just produce an error (see the section on 'Variables' subsection 'Avoiding errors with variables'). In order to solve this problem, we could write this:

if( document.body ) { if( document.body.style ) { etc. } }

However, the && operator has a useful feature that we can use here to combine the two 'if' statements into one:

if( document.body && document.body.style ) { etc. }

The first test would be false, so the browser would not proceed to the second. This is known as a short-circuit. The || operator has a similar feature, but it will only evaluate the second test if the first one fails.

JavaScript understands that if the '{' and '}' (curly brace) characters are left out, then only the next command belongs to that statement:

if( x < 5 ) x++; window.alert(x);

Here, the alert will always happen reguardless of x, but x will only be incremented if x is less than 5. This may seem convenient, as it allows you to make your code a tiny bit shorter, but I recommend avoiding this syntax. It makes your code harder to read, especially if you start nesting your control structures. It also makes it easy to forget to put them in when you needed them, and also makes debugging code much harder, since you will need to go back through your code to add them so that you can add extra debugging tests. It is best to always use the curly braces, even if they are optional.

As always, there is an exception. Nested 'if' statements like this can start to get difficult to manage:

if( myVariable == 2 ) { myVariable = 1; } else { if( myVariable == 5 ) { myVariable = 3; } else { myVariable = 4; } }

By strategically removing curly braces, that can usefully be reduced to this construct (which you may recognise from other programming languages) - note that 'else if' is not written as 'elseif':

if( myVariable == 2 ) { myVariable = 1; } else if( myVariable == 5 ) { myVariable = 3; } else { myVariable = 4; }

The 'switch' statement
The 'switch' statement is like repeated 'if' statements, testing a single value to see if it matches one of a set of values:

switch(myVar) { case 1: //if myVar is 1 this is executed case 'sample': //if myVar is 'sample' (or 1, see the next paragraph) //this is executed case false: //if myVar is false (or 1 or 'sample', see the next paragraph) //this is executed default: //if myVar does not satisfy any case, (or if it is   //1 or 'sample' or false, see the next paragraph) //this is executed }

If a case is satisfied, the code beyond that case will also be executed unless the break statement is used. In the above example, if myVar is 1, the code for case 'sample', case false and default will all be executed as well. The solution is to use break; as follows (The use of the break statement is described below).

switch(myVar) { case 1: //if myVar is 1 this is executed break; case 'sample': //if myVar is 'sample' this is executed break; case false: //if myVar is false this is executed break; default: //if myVar does not satisfy any case, this is executed //break; is unnecessary here as there are no cases following this }

The 'for' loop
This is one of the most common constructs in use. Typically, it is used to cycle through the contents of an array, or to create a specific number of new objects, but it can do many more useful things if needed. The syntax of the 'for' loop is as follows:

for( starting_initialise; continue_as_long_as_condition; do_this_each_time )

starting_initialise This is where you define new variables that you will use in the loop, typically for use with incremental counting. As with all variables, you must declare them (if you have not done so already). You can define multiple variables if needed, using:

var myVariable1 = value, myVariable2 = another_value;

These variables are not restricted to being inside the 'for' loop, and will be available to all code after the loop (in the same scope as the loop). continue_as_long_as_condition This is where you define the conditons under which the loop should continue to execute. The syntax is exactly the same as for the 'if' statement, so you can apply more than one continue condition by using the && or || operators:

myVariable1 <= 5 && myVariable2 >= 70;

If the condition is not satisfied when the for loop begins, then it will never loop through it. do_this_each_time Once the end of the loop is reached, it will do whatever you tell it to here. Typically, this is used to increment or decrement a stepping variable, and it is possible to perform actions on more than one variable by separating them with a comma:

myVariable1++, myVariable2 -= 4

The following is a full example.

for( var myVariable = 1; myVariable <= 5; myVariable++ ) { myArray[myVariable] = 1; }

myArray[1] to myArray[5] are now 1. The 'for - in' loop

The 'for - in' loop is used to cycle through all exposed properties of an object (or array). Every time you create properties or methods on an object, these will be added to the list of properties that will be exposed. Most internal properties (the ones that JavaScript creates) will also be exposed, but JavaScript engines are allowed to hide internal properties and methods if they want to. You should not rely on any specific behaviour here, but note that some browsers will give the internal properties and methods of intrinsic objects, and some will not.

Again, you should declare the variable names that you use, if you have not done so already. The syntax of the 'for - in' loop is as follows:

for( var myVariable in anObjectOrArray ) {

This will run through the loop, once for each exposed property in anObjectOrArray. Each time it loops, it assigns the next property name as a string value to myVariable. You can then use array notation to access the value of that property. The following example writes all the exposed properties of the document object:

for( var myVariable in document ) { document.write( myVariable + ' = ' + document[myVariable] + ' ' ); }

Note that if you use this loop on an array, it will list the numbered and named keys, including the internal 'length' property. It is very easy to make mistakes here, so be careful not to mistake these property types for each other.

The 'while' loop
The 'while' loop is identical in behaviour to the 'for' loop, only without the initial setup, and loop-end actions. It will continue to run as long as the condition is satisfied:

var myVariable = 1;

while( myVariable <= 5 ) { myArray[myVariable] = 1; myVariable++; }

myArray[1] to myArray[5] are now 1.

Using a feature of the increment (and decrement) operator here, it is possible to shorten the code inside the loop to be just 'myArray[myVariable++] = 1;', and it would have exactly the same effect. Firstly, it would use the value of myVariable to index the array cell, then it would increment myVariable.

This also works in reverse; 'myArray[++myVariable] = 1;'. Firstly, it would increment the value of myVariable, then it would use the new value to index the array cell. If I had done this, myArray[2] to myArray[6] would now be 1.

These features also work outside loops, but this is where you will most commonly see them, so I have included them here.

The 'do - while' loop
This is similar to the while loop, but with an important difference. The condition is evaluated at the end of the loop, meaning that even if the condition is never satisfied, it will still run through the loop at least once.

var myVariable = 1;

do { myArray[myVariable] = 1; myVariable++; } while( myVariable <= 5 );

myArray[1] to myArray[5] are now 1.

The 'with' statement
Take for example the following example:

x = Math.round( Math.LN2 + Math.E + Math.pow( y, 4 ) );

Using the 'with' statement, this can be replaced with:

with( Math ) { x = round( LN2 + E + pow( y, 4 ) ); }

Note that the 'with' statement brings extra variable names into the current scope. In the example above, if I already had a variable called pow before the 'with' statement, this variable would be unavailable inside the with statement, as it would have been replaced by the method of the Math object (as would any other variables that matched property or method names). Once the 'with' statement is complete, the old variables would become available again. The quick 'if' statement

This is known as the conditional or ternary operator, and is an easy way to assign different values to a variable, depending on a condition.

var myVariable = document.getElementById ? 1 : 0;

This is identical to:

if( document.getElementById ) { var myVariable = 1; } else { var myVariable = 0; }

The try - catch - finally statement
Netscape 4, Internet Explorer 4 and WebTV do not support this structure and will produce errors if you use it.

The 'try - catch - finally' control stucture allows you to detect errors and quietly deal with them without producing error messages or aborting the script, and in fact, without even interrupting the flow of the script that is running. This makes it superior to the original way of handling script errors (without error messages) where scripts are completely aborted:

window.onerror = referenceToFunction;

The syntax of the 'try - catch - finally' control stucture is as follows:

try { //do something that might cause an error } catch( myError ) { //if an error occurs, this code will be run //two properties will (by default) be available on the //object passed to the statement alert( myError.name + ': ' + myError.message ); } finally { //optional - this code will always be run before the //control structure ends, even if you rethrow the error //in the catch }

If an error occurs in the 'try' section, it immediately jumps to the 'catch' part, passing some information about the error. Different browsers provide different information for the same error so don't trust it (in theory, DOM browsers will use a specific set of error types, but this depends on their level of DOM support - Internet Explorer is the least compliant here). Once the 'try' or 'catch' parts have been run, the 'finally' part is run if you have provided one, then the script following the control structure is run, unless you throw another error.

If you nest these statements (one 'try - catch' inside another), you can rethrow the error from the 'catch' part of the inner statement to the 'catch' part of the outer statement (the 'finally' part - if there is one - would still be run before the outer 'catch' is run, but the script following the inner structure will not be run). This is done using the 'throw' method:

try{ //...some other code goes in here try { var a = nonexist.b; //this will produce an error } catch(myError) { //this catches the error and alerts the message alert( myError.message ); //re-throw the error up to the outer try - catch throw( myError ); } //...some other code goes in here } catch( myErrorObject ) { //I re-threw the first error, so this is the same error object //the message should be the same alert( myErrorObject.message ); }

You can also throw your own errors at any point by creating an object with the required properties, and passing it as the parameter when using throw:

try{ var myEr = new Object; myEr.name = 'My error'; myEr.message = 'You did something I didn\'t like'; throw( myEr ); } catch( detectedError ) { alert( detectedError.name + '\n' + detectedError.message ); }

What is wrong with it?

It's lack of support in older browsers was its only major failing. Thankfully these browsers are hardly used any more. It may have been useful to use this structure detect errors in Netscape 4 (like the 'this' keyword + inline method bug - for example - there are lots more errors), but that browser does not support the statement. It would also be useful for checking for stupid bugs, like where checking for something like navigator.taintEnabled causes errors in older versions of Internet Explorer. However, the error is not correctly thrown for these errors.

Unfortunately, if you use this structure in any script run by a browser that does not support it, the browser will abort the entire script with errors, even if it does not use the part containing the structure. Thankfully, these old browsers can be safely ignored.

It should never be used to detect if a browser supports a method or property like document.getElementById as a proper object detect would suffice. So when should it be used?

It can be used for W3C DOM scripting, where you may want to avoid DOM mutation errors (for example), which are valid errors, but serve to warn you not to do something, and do not always need to abort the whole script. Older browsers do not support the DOM anyway, so it doesn't matter if they don't understand this part of it. However, they will still run the script (it is not possible to protect them by using the language attribute on the script tag, as you need to use JavaScript 1.2 - not anything higher - to enable Internet Explorer 5 support). This means that the older browsers will still produce errors, unless you define the old error handling method in an earlier script.

It can be used for throwing your own errors if you create the 'error' deliberately under certain circumstances.

It can be used to check if accessing a frameset frame will cause a browser security error (for example, if the page in the frame belongs to another site).

It could also enable you to avoid problems where different browsers support the same methods but expect a different syntax, for example, the selectBox.add method (I did not include this method in my DOM section of the tutorial due to this problem):

try { selectBox.add(optionObject,otherOptionObject); } catch ( e ) { selectBox.add(optionObject,index); }

Conditionals without a condition?

You may notice in the example for "The quick 'if' statement" that I tested for a property without testing for any specific value: 'if( document.getElementById )'

That is valid, and is one of the most useful parts of JavaScript. This is a very important rule to learn, as it forms the basis of object and capability detection, and is fundamental to making cross browser scripts. This will be true if:

document.getElementById != "" && document.getElementById != 0 && document.getElementById != false && document.getElementById != undefined && document.getElementById != null

The opposite is also possible: 'if( !document.getElementById )'

This will be true if:

document.getElementById == "" || document.getElementById == 0 || document.getElementById == false || document.getElementById == undefined || document.getElementById == null

Using this, you can detect one type of capability, and if it fails, detect another type, and continue until you find one that works.

You can also do this anywhere where a condition is expected, such as with the 'while' loop condition, the 'do - while' loop condition and the 'continue_as_long_as_condition' in the for loop. Checking for properties with 'in'

WebTV crashes if you use the 'in' operator to check for a property that does not exist. Netscape 4, Internet Explorer 5.0- on Windows and Internet Explorer on Mac cannot use the 'in' operator as shown here.

The 'in' operator used in the 'for - in' loop has another purpose. It can also be used to check for the existence of named properties of an object. In most cases, it is best to use a conditional without a condition, as shown above. However, there are some cases where you want to test for the existence of a property even thought the property's value may be one that does not evaluate to true. An example would be where you want to check for the existence of a property whose value may be 0, or an empty string, or null.

If you know what the type of the property will be, it is possible to achieve this using identity operators, or the typeof operator, as shown here:

if( typeof( document.body.innerHTML ) == 'string' ) {

However, it is also possible to use the 'in' operator to test for a property. This allows you to test for its existence, no matter what value it currently holds, and no matter what type of value it currently has (even if it has been assigned a value of undefined). In the 'for - in' loop, the 'in' operator returned the name of properties as a string, and so here, it expects the name to be a string. This limits the usefulness a little, as it can only search for the name, and cannot be used to see if one of the properties holds a specific value or value type.

if( 'innerHTML' in document.body ) {

Note that this is around 20 times slower in Internet Explorer than the conditional without a condition, as shown above. In most other browsers, the two alternatives perform about the same. In general, I consider it best to use the more common alternatives, unless you have a specific use that needs the behaviour of the 'in' operator. Assignments inside a conditional

JavaScript allows you to perform an assignment at the same time as testing if the assignment worked. This can be used inside any conditional, including inside an 'if', 'for', 'while' and 'do - while'.

if( x = document.getElementById('mydiv') ) {...}

do { alert( node.tagName ); } while( node = node.parentNode );

Note that Internet Explorer on Mac will produce an error if you try to do this with an array, when it steps off the end of the array. Continue and break statements and labels Labels

Labels are used to name the 'while', 'do - while', 'for', 'for - in' and 'switch' control structures. The syntax used is:

LabelName: Control Structure

Labels are very rarely used in JavaScript. The break statement

Writing break inside a switch, for, for-in, while or do - while control structure will cause the program to jump to the end of the statement. If you just use, for example:

for( var x = 1; x < 5; x++ ) { var y = 1; while( y < 7 ) { y++; if( y == 5 ) { break; } document.write(y); } }

The script will jump past the end of the while loop when y is 5. But if you use this:

myForLoop: for( var x = 1; x < 5; x++ ) { var y = 1; while( y < 7 ) { y++; if( y == 5 ) { break myForLoop; } document.write(y); } }

The script will jump past the end of the for loop when y is 5. The continue statement

Writing continue inside a 'for', 'for - in', 'while' or 'do - while' control structure will cause the program to jump to the test condition of the structure and re-evaluate it having performed any 'do_this_each_time' instructions. If you just use this, for example:

for( var x = 1; x < 5; x++ ) { var y = 1; while( y < 7 ) { y++; if( y == 5 ) { continue; } document.write(y); } }

This script will jump to the test condition of the while loop when y is 5 so 5 will never be written but 6 and 7 will be. If you use this instead:

myForLoop: for( var x = 1; x < 5; x++ ) { var y = 1; while( y < 7 ) { y++; if( y == 5 ) { continue myForLoop; } document.write(y); } }

Here, the script will increment x as part of the for loop and then re-evaluate the for condition.