Javascript continued

literals

In Javascript, we can express numbers in hex, octal, and engineering notation:

0x6AC2               // the value hex 6AC2
027                  // the value octal 27
662.25E-4            // the value 662.25 * 10-4

Strings are written either in single- or double-quote markes. The only difference between them is that single-quote strings require you to escape any single-quote characters while double-quote strings require you to escape any double-quote characters:

‘In a single-quote string, escape the \‘ character but not the “ character.’
“In a double-quote string, escape the \“ character but not the ‘ character.”

{} as a statement

Within a function (or method), a pair of curly braces that enclose a “body” are actually what’s called a compound statement, a statement comprised of other statements. Wherever the language syntax allows a statement, you can put {} with one or more other statements inside.

So whereas previously I’ve defined the syntax of, say, while as:

while (condition) {body}

…the true syntax is:

while (condition) statement

It’s just that we usually want a loop to contain multiple statements, so we use {} with while most of the time.

In fact, many programmers insist that {} should always be used in these constructs for stylistic consistency. So though this is legal:

if (bla) foo();

…you should probably just always write:

if (bla) {
    foo();
}

I personally prefer when if’s and while’s follow this uniform indentation and always use {} whether they contain just one statement or many.

Be clear that not all pairs of {} are compound statements. The {} of a function definition, for instance, are just a part of the syntax for a function definition, not a statement of their own.

conditional operator

The conditional operator is a bit unusual because it takes three operands—a condition and two expressions—and is denoted by two separate symbols, a question mark and a colon:

condition ? expression1 : expression2

In a ?: operation, the condition is evaluated, and if true, expression1 is evaluated and its value returned; otherwise, expression2 is evaluated and its value returned.

Notice that the conditional operator is also unusual because, unlike with normal operators, not all of its operands are evaluated: either expression1 evaluates or expression2 evaluates, never both. Basically, a ?: is like an if-else in expression form, allowing us to write some compacter code. For instance, instead of writing:

if (something) {
    x = 3;
} else if {
    x = 5;
}

…we can instead write:

x = (something ? 3 : 5);

(The parens here are not necessary, but I recommend always surrounding a ?: in parens for clearer style.)

Many programmers frown upon the use of ?: because it can be hard to read, especially in complex expressions. When all branching is done with just statements like if and while, the flow of code tends to stand out more and thus be a bit easier to follow.

Because the conditional operator takes three operands, it’s also known as the “ternary operator”.

compound assignment operators

Very commonly, we perform an operation upon a variable’s value and then assign the result to that same variable:

foo = foo + 3;

Because this is so common, we have a more compact syntax:

foo += 3;

The general form is:

variable op= expression;

…which converts to:

variable = variable op (expression);

This works not just for the + operator but for several other operators, e.g.:

foo /= 3;    // foo = foo / (3)

increment and decrement operators

Because incrementing and decrementing variables is so common, we have the unary ++ (increment) and — (decrement) operators:

foo++;   // (foo = foo + 1)
bar--;   // (bar = bar – 1)

The odd thing about ++ and — is that they come in prefix forms as well as postfix:

++foo;   // prefix form (foo = foo + 1)
--bar;   // prefix form (bar = bar – 1)

The difference between the prefix and postfix forms is what value gets returned: the postfix forms return the value which the variable had before the increment or decrement; the prefix forms return the value which the variable has after the increment or decrement:

int x = 3;
int foo = x++;    // x++ returns 3

int x = 3;
int foo = ++x;    // ++x returns 4

In both cases here, x increments from 3 to 4; just the values returned differ.

The use of increment and decrement can get confusing in complex expressions. To avoid this confusion, most programmers simply only use ++ and — in isolated statements where it doesn’t matter whether you use the prefix or postfix forms:

++foo;      // just as well might write foo++ here instead

Be clear that the increment and decrement operators are effectively kinds of assignment and so only work on “lvalues” (things to which you can assign):

int x = ++3;     // compile error: ++3 is an invalid expression

break and continue

A break statement is simply written:

break;

Within a loop, a break statement jumps execution out of the loop:

while (bla) {
…
}
foo();  // execution jumps here after a break in the loop

It never makes sense to execute a break unconditionally because any statement(s) immediately after a break would never execute:

break;
bar();  // this would never execute

So break only makes sense as the last statement within a conditional branch:

if (something) {
    break;
}
bar();

A continue statement is like break, except continue jumps execution back to the condition for re-testing instead of terminating the loop:

continue;

A continue basically says to skip the rest of the current iteration.

If we didn’t have break and continue, we could get the same control flow just using “control” variables in our loop conditions, but break and continue often express the same logic more elegantly.

switch

Commonly we wish to choose a mutually exclusive branch upon a value, such as a variable x:

if (x == 3) {
      body1
} else if (x == -45) {
      body2
} else if (x == 100) {
      body3
} else {
      body4
}

Above, which body executes depends upon the value of x. The switch construct expresses this a bit more succinctly:

switch (x) {
case 3:
       body1
case -45:
      body2
case 100:
      body3
default:
      body4
}

(The default case executes only when the value matches no other value. A default case is optional, and it needn’t be written last, though doing so usually makes most sense.)

However, this isn’t quite equivalent. A quirk of switch is that execution “falls through” from one case to the next until a break is encountered. So the proper equivalent of the above if-else ladder is written as a switch like so:

switch (x) {
case 3:
           body1
    break;
case -45:
           body2
    break;
case 100:
           body3
    break;
default:
           body4
    break;
}

Above, if we were to omit the break after body2, then when valueExpression returns -45, body2 would execute and then continue through body3 until execution encounters a break. Very occasionally, you might find this fall through behavior desirable, but mostly it just annoys programmers who forget to end each case with a break statement. (Also note that the break after the last body isn’t necessary, but I write it there just for stylistic consistency.)

A switch is really just a more constrained form of if-else and doesn’t really do anything an if-else doesn’t. I recommend you always favor if-else over switch because it’s just not worth the hassle deciding when a switch might make your code minutely more elegant or efficient.

do-while loop

The do-while loop is a simple varient of while that simply puts the condition at the end of the loop such that the loop is entered the first time unconditionally:

do statement while (condition);

(Note the semi-colon at the end.)

A do-while is intended for those times when you want a loop to always execute at least once. The thinking is that, rather than writing:

doStuff();
while (something) {
    doStuff();
}

…you can just write:

do {
    doStuff();
} while (something);

…thus sparing the repetition of the body of the loop.

In practice, I find that do-while, like switch, is not terribly useful.

for loop

The for loop is another variant of while, but it tends to get used much more often than do-while:

for (expression1 ; condition ; expression2) statement

As you can see, for differs from while by the addition of two expressions surrounding the condition, separated by semi-colons (which you should think of as unrelated to the use of semi-colons to terminate a statement: the semi-colons here just divide the expressions from the condition). The first expression is evaluated only once, before the condition is first tested. The second expression is evaluated after each run through the body. The while loop equivalent would be:

expression1;
while (condition) {
    … // body statements
          expression2;
}

So the for loop really just exists to compact our code into fewer lines. Consider this while:

var i = 0;
while (i < 5) {
    foo(i);
    i++;
}

The for equivalent is written:

var i;
for (i = 0; i < 5; i++) {
    foo(i);
}

The expression before the condition can be a declaration, so we can make this even more compact:

for (var i = 0; i < 5; i++) {
    foo(i);
}

Basically, any time you need to iterate a counter, a for is the preferred choice of loop.

compound declarations

In Javascript, we can declare multiple variables in one statement by listing multiple names separated by commas:

var buffy, xander, willow;     // declare three variables

We can initialize any variable in a compound declaration:

var buffy, xander = 3, willow;

string concatenation with +

The + operator in Javascript is polymorphic: for number operands, it does addition as you expect, but when at least one operand is not a number, + returns a new string which is the concatenation of the operands:

‘moo’ + ‘cow’                 // ‘moocow’
-72 + ‘hello’                 // ‘-72hello’

Concatenation of a non-string operand first gets its string representation by invoking its toString method. For numbers and booleans, what toString returns is quite obvious, e.g. toString invoked upon -72 returns ‘-72’, and toString invoked upon true returns ‘true’. The default toString method of objects returns an empty string. For types of your own creation, you may wish to define their toString method to return something more helpful.

Be clear that concatenation doesn’t modify the operands but rather produces a new string based upon the operands. (Recall that strings in Javascript are always immutable and so can’t be changed by any operation.)

relational operators

In Javascript, < > <= and >= can be used to compare strings:

“hello” < “jello” // true: ‘h’ has a lower Unicode value than ‘j’
“feet” < “feed”   // false: ‘t’ has a higher Unicode value than ‘d’
“moo” > “moo”           // false: all characters match, so neither string is greater

The comparison is based on the first non-matching pair of characters: the lesser string is the string with the lesser value Unicode character.

equality operators

Javascript has === and !== in addition to == and !=. The == and != operators will attempt certain type conversions whereas === and !== strictly return true only when both operands are of the same type. For example:

“5” == 5    // true
“5” === 5   // false

In the == comparison, the string representation of 5 is used for the comparison, so the comparison returns true. The === comparison compares the operands as given and so returns false here.

It’s probably best just to avoid using Javascript’s == and != because their implicit conversion behavior is usually just an unwelcome surprise. Use === and !== instead.

logical operators

Instead of returning the proper boolean value, Javascript’s && and || operators return an operand with the appropriate truth value. This requires explanation:

First off, recall that in Javascript, the values false, null, 0, “” (empty string), and undefined are all considered false while all other values are considered true. So the logical operators can actually take any kind of values as operands. Now consider:

x && y

In this expression, if we test x and find that is false, then && should return false because we already know, looking at just one operand, that not both operands are true. And if every value represents its own truth value, then && can return the value of x itself instead of returning the boolean value false.

Conversely, if we test x and find that is true, then && should return the value y: when we already know x is true, then both operands will be true when y is true, and both operands will not be true when y is false.

So consider examples:

null && 19        // null (which has the truth value false)
2 && 19           // 19 (which has the truth value true)

Similarly,  in x || y, when x is false, we return y, but when x is true, we return x:

null || 19        // returns 19 (which has the truth value true)
2 || 19           // returns 2 (which has the truth value true)
0 || false        // returns false (which has the truth value false)

bitwise operators

Javascript has binary operators for bitwise operations upon integers:

  • ~             (bitwise not, unary)
  • &             (bitwise and, binary)
  • |              (bitwise or, binary)
  • ^             (bitwise xor, binary)
  • <<           (bitwise left shift, binary)
  • >>           (bitwise right shift, binary)

Wikipedia gives a good explanation of these operations.

for-in loop

Javascript has a variant of for called for-in, written:

for (variable in expression) statement

…where variable is the name of a variable (or a declaration of one) and expression returns a Javascript object or array. In each iteration, variable will be assigned the next index of the object or array; the loop ends after the iteration of the last index.

var x = [“bla”, 35, true];
for (var i in x) {
    foo(i);
}

Above, the loop calls foo three times, first with argument 0, then 1, then 2. This next time, foo is called with “bla”, then 35, then true:

var x = [“bla”, 35, true];
for (var i in x) {
    foo(x[i]);
}

Comments are closed.