Chapter 3. Statements and Expressions

Statements such as if and for can be used in two ways in JavaScript, with curly braces for multiple contained lines or without curly braces for one contained line. For example:

// Bad, though technically valid JavaScript
if(condition)
    doSomething();

// Bad, though technically valid JavaScript
if(condition) doSomething();

// Good
if (condition) {
    doSomething();
}

// Bad, though technically valid JavaScript
if (condition) { doSomething(); }

The first two forms, which use an if statement without braces, are explicitly disallowed in Crockford’s Code Conventions, the jQuery Core Style Guide, the SproutCore Style Guide, and the Dojo Style Guide. The omission of braces also generates warnings by default in both JSLint and JSHint.

An overwhelming majority of JavaScript developers are in agreement that block statements should always use braces and always occupy multiple lines instead of one. This is because of the confusion created when braces aren’t included. Consider the following:

if (condition)
    doSomething();
    doSomethingElse();

It’s difficult to tell the author’s intent in this code. There’s clearly an error here, but it’s impossible to know whether the error is an indentation error (the last line should not be indented) or braces are missing because both line 2 and line 3 need to be executed inside the if statement. Adding braces makes the error easier to find. Here are two other examples with errors:

if (condition) {
    doSomething();
}
    doSomethingElse();

if (condition) {
    doSomething();
doSomethingElse();
}

In both of these examples, the code error is clear, as both obviously have indentation errors. The braces allow you to very quickly determine the author’s intent and make an appropriate change without fear of changing the code logic.

Braces should be used for all block statements, including:

  • if

  • for

  • while

  • do...while

  • try...catch...finally

Brace Alignment

A second topic related to block statements is the alignment of braces. There are two main styles of brace alignment. The first is to have the opening brace on the same line as the beginning of the block statement, as in this example:

if (condition) {
    doSomething();
} else {
    doSomethingElse();
}

JavaScript inherited this style from Java, where it is documented in the Code Conventions for the Java Programming Language. This style also now appears in Crockford’s Code Conventions, the jQuery Core Style Guide, the SproutCore Style Guide, the Google JavaScript Style Guide, and the Dojo Style Guide.

The second style of brace alignment places the opening brace on the line following the beginning of the block statement, as in this example:

if (condition)
{
    doSomething();
}
else
{
    doSomethingElse();
}

This style was made popular by C#, as Visual Studio enforces this alignment. There are no major JavaScript guides that recommend this style, and the Google JavaScript Style Guide explicitly forbids it due to fears of automatic semicolon insertion errors. My recommendation is to use the previous brace alignment format.

Block Statement Spacing

Spacing around the first line of a block statement is also a matter of preference. There are three primary styles for block statement spacing. The first is to have no spaces separating the statement name, the opening parenthesis, and the opening brace:

if(condition){
    doSomething();
}

This style is preferred by some programmers because it is more compact, though some complain that the compactness actually inhibits legibility. The Dojo Style Guide recommends this style.

The second style is to have a space separation before the opening parenthesis and after the closing parenthesis, such as:

if (condition) {
    doSomething();
}

Some programmers prefer this style because it makes the statement type and condition more legible. This is the style recommended by Crockford’s Code Conventions and the Google JavaScript Style Guide.

The third style adds spaces after the opening parenthesis and before the closing parenthesis, as in the following:

if ( condition ) {
    doSomething();
}

This is the style prescribed in the jQuery Core Style Guide, because it makes all aspects of the statement start quite clear and legible.

I prefer the second style as a nice compromise between the first and third styles.

The switch Statement

Developers tend to have a love-hate relationship with the switch statement. There are varying ideas about how to use switch statements and how to format them. Some of this variance comes from the switch statement’s lineage, originating in C and making its way through Java into JavaScript without the exact same syntax.

Despite the similar syntax, JavaScript switch statements behave differently than in other languages: any type of value may be used in a switch statement, and any expression can be used as a valid case. Other languages require the use of primitive values and constants, respectively.

Indentation

Indentation of the switch statement is a matter of debate among JavaScript developers. Many use the Java style of formatting switch statements, which looks like this:

switch(condition) {
    case "first":
        // code
        break;

    case "second":
        // code
        break;

    case "third":
        // code
        break;

    default:
        // code
}

The unique parts of this format are:

  • Each case statement is indented one level from the switch keyword.

  • There is an extra line before and after each case statement from the second one on.

The format of switch statements is rarely included in style guides when this style is used, primarily because it is the format that many editors use automatically.

Although this is the format that I prefer, both Crockford’s Code Conventions and the Dojo Style Guide recommend a slightly different format:

switch(condition) {    
case "first":
    // code
    break;        
case "second":
    // code
    break;        
case "third":
    // code
    break;    
default:
    // code
}

The major difference between this and the previous format is that the case keyword is aligned to the same column as the switch keyword. Note also that there are no blank lines in between any parts of the statement. JSLint expects this indentation format for switch statements by default and will warn if a case is not aligned with switch. This option may also be turned on and off via the “Tolerate messy white space” option. JSLint does not warn if additional blank lines are included.

As with other aspects of coding style, this choice is completely a matter of preference.

Falling Through

Another popular source of debate is whether falling through from one case to another is an acceptable practice. Accidentally omitting a break at the end of a case is a very common source of bugs, so Douglas Crockford argues that every case should end with break, return, or throw, without exception. JSLint warns when one case falls through into another.

I agree with those who consider falling through to be an acceptable method of programming, as long as it is clearly indicated, such as:

switch(condition) {

    // obvious fall through
    case "first":
    case "second":
        // code
        break;

    case "third":
        // code

        /*falls through*/        
    default:
        // code
}

This switch statement has two obvious fall-throughs. The first case falls through into the second, which is considered an acceptable practice (even by JSLint) because there are no statements to run for just the first case and there are no extra lines separating the two case statements.

The second instance is with case "third", which falls through into the default handler. This fall-through is marked with a comment to indicate developer intent. In this code, it’s obvious that the case is meant to fall through and isn’t a mistake. JSHint typically warns when a case falls through unless you include this comment, in which case the warning is turned off because you’ve signaled that this isn’t an error.

Crockford’s Code Conventions disallows fall-throughs in switch statements altogether. The jQuery Core Style Guide mentions that fall-throughs are used in their code, and the Dojo Style Guide gives an example with a fall-through comment. My recommendation is to allow fall-throughs as long as a comment is used to indicate that the fall-through is intentional.

default

Another point of contention with regard to switch is whether a default case is required. Some believe that a default should always be included even if the default action is to do nothing, as in:

switch(condition) {
    case "first":
        // code
        break;

    case "second":
        // code
        break;

    default:
        // do nothing
}

You’re likely to find open source JavaScript code following this pattern, including default and just leaving a comment that nothing should happen there. Although no style guides are explicit about this, both Douglas Crockford’s Code Conventions for the JavaScript Programming Language and the Dojo Style Guide include default as part of their standard switch statement format.

My preference is to omit default when there is no default action and annotate it using a comment, as in this example:

switch(condition) {
    case "first":
        // code
        break;

    case "second":
        // code
        break;

    // no default
}

This way, the code author’s intent is clear that there should be no default action, and you save some bytes by not including extra unnecessary syntax.

The with Statement

The with statement changes how the containing context interprets variables. It allows properties and methods from a particular object to be accessed as if they were local variables and functions, omitting the object identifier altogether. The intent of with was to lessen the amount of typing developers need to do when using multiple object members in close proximity. For example:

var book = {
    title: "Maintainable JavaScript",
    author: "Nicholas C. Zakas"
};

var message = "The book is ";

with (book) {
    message += title;
    message += " by " + author;
}

In this code, the with statement is used to augment identifier resolution within the curly braces by allowing the properties of book to be accessed as if they were variables. The problem is that it’s hard to tell where title and author originated from. It’s not clear that these are properties of book and that message is a local variable. This confusion actually extends far beyond developers, with JavaScript engines and minifiers being forced to skip optimization of this section for fear of guessing incorrectly.

The with statement is actually disallowed in strict mode, causing a syntax error and indicating the ECMAScript committee’s belief that with should no longer be used. Crockford’s Code Conventions and the Google JavaScript Style Guide disallow the use of with. I strongly recommend avoiding the with statement, as it prevents you from easily applying strict mode to your code (a practice I recommend).

The for Loop

There are two types of for loops: the traditional for loop that JavaScript inherited from C and Java, as well as the for-in loop that iterates over properties for an object. These two loops, though similar, have two very different uses. The traditional for loop is typically used to iterate over members of an array, such as:

var values = [ 1, 2, 3, 4, 5, 6, 7 ],
    i, len;

for (i=0, len=values.length; i < len; i++) {
    process(values[i]);
}

There are two ways to modify how the loop proceeds (aside from using a return or throw statement). The first is to use the break statement. Using break causes the loop to exit immediately and not continue running even if the loop hasn’t finished all iterations. For example:

var values = [ 1, 2, 3, 4, 5, 6, 7 ],
    i, len;

for (i=0, len=values.length; i < len; i++) {
    if (i == 2) {
        break;  // no more iterations
    }
    process(values[i]);
}

The body of this loop will execute two times and then exit before executing process() the third time, even if the values array has more than three items.

The second way to modify how a loop proceeds is through the use of continue. The continue statement exits the loop immediately; however, the loop will continue with the next iteration. Here’s an example:

var values = [ 1, 2, 3, 4, 5, 6, 7 ],
    i, len;

for (i=0, len=values.length; i < len; i++) {
    if (i == 2) {
        continue;   // skip just this iteration
    }
    process(values[i]);
}

The body of this loop executes two times, skips the third time, and picks up with the fourth iteration. The loop will then continue until its last iteration unless otherwise interfered with.

Crockford’s Code Conventions disallows the use of continue. His assertion is that code using continue can better be written using conditions. For instance, the previous example can be rewritten as:

var values = [ 1, 2, 3, 4, 5, 6, 7 ],
    i, len;

for (i=0, len=values.length; i < len; i++) {
    if (i != 2) {           
        process(values[i]);
    }
}

Crockford argues that this pattern is easier for developers to understand and less error prone. The Dojo Style Guide states explicitly that continue, along with break, may be used. My recommendation is to avoid continue whenever possible, but there is no reason to completely forbid it. The readability of the code should dictate its usage.

JSLint warns when continue is used. JSHint does not warn when continue is used.

The for-in Loop

The for-in loop is used to iterate over properties of an object. Instead of defining a control condition, the loop systematically goes through each named object property and returns the property name inside of a variable, as in:

var prop;

for (prop in object) {
    console.log("Property name is " + prop);
    console.log("Property value is " + object[prop]);
}

A problem with for-in is that it returns not only instance properties of an object but also all properties it inherits through the prototype. You may thus end up with unanticipated results when iterating through properties on your own object. For this reason, it’s best to filter the for-in loop to only instance properties by using hasOwnProperty(). Here’s an example:

var prop;

for (prop in object) {
    if (object.hasOwnProperty(prop)) {
        console.log("Property name is " + prop);
        console.log("Property value is " + object[prop]);
    }
}

Crockford’s Code Conventions require the use of hasOwnProperty() for all for-in loops. Both JSLint and JSHint warn when a for-in loop is missing a call to hasOwnProperty() by default (both allow this option to be turned off). My recommendation is to always use hasOwnProperty() for for-in loops unless you’re intentionally looking up the prototype chain, in which case it should be indicated with a comment, such as:

var prop;

for (prop in object) {   // include prototype properties
    console.log("Property name is " + prop);
    console.log("Property value is " + object[prop]);
}

Another area of focus with for-in loops is their usage with objects. A common mistake is to use for-in to iterate over members of an array, as in this example:

// Bad
var values = [ 1, 2, 3, 4, 5, 6, 7],
    i;

for (i in values) {
    process(items[i]);
}

This practice is disallowed in Crockford’s Code Conventions as well as the Google JavaScript Style Guide due to the potential errors it may cause. Remember, the for-in is iterating over object keys on both the instance and the prototype, so it’s not limited to the numerically indexed properties of the array. The for-in loop should never be used in this way.