Wednesday, 11 February 2015

control structures in javascript

control structures in javascript

The 'if' statement

The if statement is straight forward - if the given expression is true, the statement or statements will be executed. Otherwise, they are skipped.
if (a === b) {
  document.body.innerHTML += "a equals b";
}
The if statement may also consist of multiple parts, incorporating else and else if sections. These keywords are part of the ifstatement, and identify the code blocks that are executed if the preceding condition is false.
if (a === b) {
  document.body.innerHTML += "a equals b";
} else if (a === c) {
  document.body.innerHTML += "a equals c";
} else {
  document.body.innerHTML += "a does not equal either b or c";
}
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.stylewhile 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 'for' loop

The for statement allows greater control over the condition of iteration. While it has a conditional statement, it also allows a pre-loop statement, and post-loop increment without affecting the condition. The initial expression is executed once, and the conditional is always checked at the beginning of each loop. At the end of the loop, the increment statement executes before the condition is checked once again. The syntax is:
for (<initial expression>;<condition>;<final expression>)
The for statement is usually used for integer counters:
var c;
for (c = 0; c < 10; c += 1) {
  // ...
}
While the increment statement is normally used to increase a variable by one per loop iteration, it can contain any statement, such as one that decreases the counter.
Break and continue are both recognized. The continue statement will still execute the increment statement before the condition is checked
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 inanObjectOrArray. 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] + '<br>' );
}
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 statement executes a given statement as long as a given expression is true. For example, the code block below will increase the variable c to 10:

while (c < 10) {
  c += 1;
  // ...
}
This control loop also recognizes the break and continue keywords. The break keyword causes the immediate termination of the loop, allowing for the loop to terminate from anywhere within the block.
The continue keyword finishes the current iteration of the while block or statement, and checks the condition to see if it is true. If it is true, the loop commences again.
  • 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

  • The do ... while statement executes a given statement as long as a given expression is true - however, unlike the while statement, this control structure will always execute the statement or block at least once. For example, the code block below will increase the variable c to 10:
do {
  c += 1;
} while (c < 10);
As with while, break and continue are both recognized and operate in the same manner. break exits the loop, and continue checks the condition before attempting to restart the 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 'switch' statement

  • The switch statement evaluates an expression, and determines flow control based on the result of the expression:

switch(i) {
case 1:
  // ...
  break;
case 2:
  // ...
  break;
default:
  // ...
  break;
}
When i gets evaluated, it's value is checked against each of the case labels. These case labels appear in the switchstatement and, if the value for the case matches i, continues the execution at that point. If none of the case labels match, execution continues at the default label (or skips the switch statement entirely if none is present.)
Case labels may only have constants as part of their condition.
The break keyword exits the switch statement, and appears at the end of each case in order to prevent undesired code from executing. While the break keyword may be omitted (for example, you want a block of code executed for multiple cases), it may be considered bad practice doing so.
The continue keyword does not apply to switch statements.
  • 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:
    
  case 'sample':
    
  case false:
   
  default:
    
}
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:
    
    break;
  case 'sample':
    
    break;
  case false:
    
    break;
  default:
    
}

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 {
  
} catch( myError ) {
  
  alert( myError.name + ': ' + myError.message );
} finally {
  
}
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{
  
  try {
    var a = nonexist.b; 
  } catch(myError) {
    
    alert( myError.message );
    
    throw( myError );
  }
  
} catch( myErrorObject ) {
  
  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.addmethod (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);
  }
}

H

No comments:

Post a Comment