Automatic semicolon insertion in JavaScript

Update 2011-11-11:What JavaScript would be like with significant newlines

In JavaScript, automatic semicolon insertion allows one to omit a semicolon at the end of a line. While you always should write semicolons, knowing how JavaScript handles their omission is important knowledge, because it helps you understand code without semicolons and because it has effects even in code with semicolons.

Background: JavaScript syntax

First, a few syntactic phenomena need to be explained that are relevant for the remainder of this post.

Expression versus statement:

Statements that have to be terminated by a semicolon: Every statement in JavaScript is terminated by a semicolon, except the following ones. Example: while versus do-while
    while(a > 0) {
        a--;
    } // no semicolon
    
    do {
        a--;
    } while(a > 0);
Example: function declaration versus function expression.
    function foo() {
    } // no semicolon
    
    var foo = function() {
    };
Note: if you do add a semicolon after the above mentioned statements, you do not get a syntax error, because it is considered an empty statement (see below).

The empty statement. A semicolon on its own is an empty statement and does nothing. Empty statements can appear anywhere a statement is expected. They are useful in situations where a statement is demanded, but not needed. In such situations, blocks are usually also allowed, but an empty block is longer than a semicolon. Example: The following two statements are equivalent.

    while(processNextItem() > 0);
    while(processNextItem() > 0) {}
The function processNextItem is assumed to return the number of remaining items. The following program is also syntactically correct: three empty statements.
    ;;;

Expressions as statements. Any expression can become a statement. Then it has to be terminated by a semicolon. Example:

    "hello world";
    a + b;
    sum(5, 3);
    a++;
All of the above are expression statements. The first two have no effect.

The rules of automatic semicolon insertion (ASI)

“Semicolon insertion” is just a term. It does not necessarily mean that actual semicolons are inserted into the source code during parsing. Instead, it is a nice metaphor for explaining when semicolons are optional.

The norm: The parser treats every new token as part of the current statement, unless there is a semicolon that terminates it. The following examples show code where you might think a semicolon should be inserted, but isn’t. This illustrates the risks of omitting semicolons.

No ASI:

    a = b + c
    (d + e).print()
This does not trigger ASI, because the opening parenthesis could follow c in a function call. The above is thus interpreted as:
    a = b + c(d + e).print();
No ASI:
    a = b
    /hi/g.exec(c).map(d);
No semicolon is inserted, the second line is not interpreted as a regular expression literal. Instead, the above is equivalent to:
    a = b / hi / g.exec(c).map(d);        
No ASI:
    var foo = "bar"
    [ "red", "green" ].foreach(function(c) { console.log(c) })
No semicolon is inserted. Instead, the beginning of the second line is interpreted as an index for the string "bar"; the comma is allowed due to the comma operator (which evaluates both its left-hand side and its right-hand side and returns its right-hand side).

No ASI: In many browsers, the code below assigns 0 to func, because a++ is interpreted as the argument of an invocation of the function in the previous line.

    var a = 0;
    var func = function(x) { return x }
    (a++)

Exceptions to the norm: ASI is applied in the following cases.

Cases where ASI is not performed:

Recommendations

Related reading

  1. ECMAScript Language Specification, 5th edition, section 7.9. [Source of this post and of some of the examples.]
  2. JavaScript Semicolon Insertion [In-depth coverage, inspiration for the section on empty statements and the ++ example.]