JavaScript Statements & Structures


In the first page we looked at the smallest elements of a program, the constants, variables, and operators, from which we made expressions, and touched on assignment statements. Now we look at statements in general, and how to form them into larger program structures. Before OOPS became the buzzword du jour, "structured programming" was the way to describe forming statements into programs in a disciplined manner. In the next section we will look at the largest program structures, called functions.

There are three kinds of simple statement -- technically, it's only one: an optional expression followed by a semicolon -- but I prefer to think of assignments as fundamentally different from function calls and jumps. Function calls we will cover in the next page, and we have seen all there is to see about assignments when we discussed variables. By the way, a semicolon by itself counts as a valid statement.

Every programming language has its own defined ways to put statements together thereby to execute one after the other in sequence, to decide whether to do something or not based on some condition, or else to do the same thing over and over repeatedly (called iteration). JavaScript sequence is simple: you just put them one after another, as we have already seen. Because every simple statement ends in a semicolon, C-based languages like JavaScript have no problem knowing when one stops and the next begins.

We can group statements into a block by enclosing them in (curly) braces, and the whole block counts as one statement for inclusion in other structures. One way to get an empty statement (which does nothing, usually as a placeholder for code to be added later) is a pair of braces {} with nothing enclosed. This is considered better than a semicolon by itself, because it's less likely to be a mistake (bug). Programmers often consider the braces to be an essential part of other structures, but the braces are only required in switch statements and function definitions. Most programmers put their braces on a line by themselves, with the nested code indented.
 

Conditionals

The basic JavaScript conditional is the if-else statement. The form is this:
if (expression) statement else statement
The expression can be as simple or complicated as you like, but it should have a value of true or false, or at least be convertable to a boolean value (a non-zero value or non-trivial string counts as true, zero or the empty string is false, but it's sloppy programming to depend on the conversion). Usually we put a boolean variable or a comparison expression there, but sometimes it is useful to combine them with logical ANDs and ORs. Don't forget to use parentheses with logical operators: a Java compiler will sometimes warn you if you got the precedence wrong because the types won't match, but C and JavaScript will just muddle through, giving you unexpected or wrong results.

The two statements in a conditional can be any valid statement, including other conditionals. The else and second statement may be omitted, which leads to a curious problem when you try to nest compound if statements without braces. All of the examples below are valid conditionals, but the last two behave differently:

if (x<5) myVar = 1; else myVar = 2;

if ((x<5) || (x>9)) myVar = 7;

if (false) {} else {} // empty statements

if (boolVar) // boolVar given a value earlier (this and the next 4 lines together)
{
  myVar = 3;
  x = 5+myVar;
}

if (boolVar) if (x<5) myVar = 1; else myVar = 2;

if (boolVar) {if (x<5) myVar = 1;} else myVar = 2;

You could try some of these out in your Test program to see what happens. If you have trouble figuring out how to do that, look here for a hint. If you get something wrong, the interpreter might try to muddle through (giving an unexpected result), or it could just stop and do nothing (and you'd see a blank page).

Often it is useful to test a single variable for multiple different values, with a different snippet of code to be executed for each different value. If we nest conditionals, it might look like this:

if (x==0) document.write("none");
else if (x==1) document.write("one");
else if (x==2) document.write("two");
else if (x==3) document.write("three");
else if (x==4) document.write("four");
else if (x==5) document.write("five");
else if (x>5) document.write("many");
If you had multiple statements for each condition, you need braces, so it might look like this:
if (x==0)
{
  myVar = 0;
  document.write("none");
}
else if (x==1)
{
  myVar = 2;
  document.write("one");
}
else if (x==2) // etc.
The switch statement cleans that up considerably. Its form:
switch (expression) {
  case const1:
    statements1
    break;
  case const2:
    statements2
    break;
  ...
  default:
    statements
    break;}
When the switch statement executes, the expression is compared to each case constant. If it is equal to const1, then statements1 are executed, and so on. The default clause is optional; if you omit it, then nothing happens when the expression does not equal any of the case constants. Actually the break statements are optional too, but you should always put them in; otherwise it just continues execution with the next case clause, which is bad form. Here's our example as a switch:
switch (x)
{
  case 0:
    myVar = 0;
    document.write("none");
    break;
  case 1:
    myVar = 2;
    document.write("one");
    break;
  case 2:
    document.write("two");
    break;
  case 3:
    document.write("three");
    break;
  case 4:
    document.write("four");
    break;
  case 5:
    document.write("five");
    break;
  default:
    document.write("many");
    break;
}

Iteration

The other kind of control structure lets us repeat the same code multiple times. Computers are mostly only useful if they can do the same boring thing over and over without being told to do it each time. The general form for this is the while-loop:
while (expression) statement
Almost always we want to do several things inside the loop, so we use a block statement there. The expression is a boolean value, and the statement is executed continuously, once each time the expression evaluates to true. Usually something inside the loop alters a variable being tested in the expression, so that the loop eventually stops because the expression becomes false. If it is false to start with, then the statement doesn't execute at all.

If the expression never becomes false, we have an infinite loop, which is almost always a bug in JavaScript. In other environments we might want the program to run continuously forever. If you make a mistake and your loop runs too long (or never terminates), there might be a Stop Loading button or menu item that will terminate it. If nothing else works, you might control-Alt-Delete to force-quit the browser, or press and hold the power button on your computer until it shuts down -- but that is always a last resort that may damage other data.

Often you will find that the best place to end the iteration is from somewhere in the middle of the loop. Normally we put it inside a conditional that determines it is time to exit, like the second example below. The break statement breaks out of the loop immediately, regardless of whether the loop condition expression is true or false. Alternatively, it may be convenient to jump back and start the loop over with the next iteration before finishing everything there; we use the continue statement for that, as in the final example below. The continue statement always retests the condition before executing the beginning of the loop, so if it's now false, it exits anyway.

Here are some examples of while-loops, which you can try out:

var myVar = 3;
while (myVar>0) myVar--; // executes 3 times, leaves 0 in myVar

myVar = 0;
while (true) // executes five times
{
  if (myVar>4) break;
  document.write("myVar = "+myVar+"<p>"); // "<p>" starts new line
  myVar++;
}

myVar = -3;
while (myVar>0) myVar--; // does not execute at all

myVar = 5;
while (true)
{
  if (myVar<0) break;
  document.write("<p>myVar = "+myVar);
  myVar--;
  if (myVar != 3) continue;
  document.write(" special case for 3");
}

If you tried that last example, were you surprised by the result? What do you suppose happened? It surprised me too. Let's see if we can figure out what went wrong.

The first time through, myVar is 5, so it does not break, but instead displays "myVar = 5" on a fresh line. Then myVar is decremented to 4, which is unequal to 3, so it jumps back to the beginning. Now myVar is 4, so we get another fresh line displayed, and then decrement myVar to 3. Of course when it is tested against 3 this time, it is equal, so the extra text is displayed on the same line before looping back to the front again. I wanted that on the "myVar = 3" line; what can we do to fix this bug? Stop and think about it before reading on.

There are several conceivable fixes.

We could change the continue test to be if (myVar != 2) ... so it catches it later in the loop. That's ugly, but it works.

We could try moving the decrement to before the first display line, but then the numbers displayed are different.

If we move the decrement to after the continue test, it gets stuck in an infinite loop, because the continue always loops back to the front without ever changing myVar.

Or we can change the structure, so instead of continue, it conditionally displays the extra information, then move the decrement after it, thus:

var myVar = 5;
while (true)
{
  if (myVar<0) break;
  document.write("<p>myVar = "+myVar);
  if (myVar == 3) document.write(" special case for 3");
  myVar--;
}
That does not demonstrate using continue, but it fixes the bug in an elegant way. The process we went through here is called debugging, and you will spend a lot of your programming time doing it. See Debugging JavaScript for more ideas on this topic.

I commonly use what looks like it might be an infinite loop to execute a sequence of conditionals where each depends on something done earlier in the sequence, but as soon as one of the computations fails (or succeeds, if I'm trying different things in the hope that one will work) I break out of the loop. A break at the end also guarantees that the loop never actually repeats. You can see several examples of this in my JavaScript interpreter. (look for lines containing "while (true) {").
 

For-loops

All of our examples so far have been stepping a single variable, and then testing that variable for a termination condition. This is so common, there is a convenient loop structure to put all the control in one line. It is logically equivalent to the while loop, but less likely to get stuck or do surprising things. Here is the form:
for (assignment; test; increment) statement
The increment part could be either an increment or decrement, as in the examples. The test part is the same boolean expression you would have used in a while loop, and the assignment part is the same as the line before the while in the examples above. If the control variable is only used within the for-loop, it's a good idea to declare it with "var". Here are those same examples as for-loops:
 
for (myVar=3; myVar>0; myVar--) {} // executes 3 times, leaves 0 in myVar

for (myVar=0; myVar<=4; myVar++) // executes 5 times
  document.write("myVar = "+myVar+"<p>"); // braces not needed for single line

for (myVar=-3; myVar>0; myVar--) {} // does not execute at all

for (myVar=5; myVar>=0; myVar--)
{
  document.write("<p>myVar = "+myVar);
  if (myVar != 3) continue;
  document.write(" special case for 3");
}

Notice we no longer have the bug in the last example, because the built-in decrement always happens after the continue but before the loop test.

Later we will look at some repetitive data structures which it makes sense to use for-loops to process sequentially.

You should be aware that in the for-loop, the assignment and the test and the increment do not need to refer to the same variable. The interpreter will not complain if you put there any other expressions or none at all, but that would be very bad form. Both of these variations produced the same output in my browser (as they would in C or Java):

var myVar = 5;
var z = 0;
for (z==0;true;x+myVar) // z==0 tests, not assigns, x+myVar does nothing!
{
  if (myVar<0) break;
  document.write("<p>myVar = "+myVar);
  if (myVar == 3) document.write(" special case for 3");
  myVar--;
}

myVar = 5;
for (;;)
{
  if (myVar<0) break;
  document.write("<p>myVar = "+myVar);
  if (myVar == 3) document.write(" special case for 3");
  myVar--;
}

I mention them only because they are legal, and nobody complains except the imaginary thought police. Don't go there anyway.

Next: Functions

Tom Pittman
Rev 2010 December 24