Sunday, March 13, 2011

JavaScript Parser - Sometimes Intelligence causes problems...



JavaScript parser automatically inserts semicolon whenever   it encounters a   parse error due to missing semicolons.

var foo = function() {
} // parse error, semicolon expected
test()
Insertion happens, and the parser tries again.
var foo = function() {
}; // no error, parser continues
test()
The automatic insertion of semicolon is considered to be one of biggest design flaws in the language, as it can change the behavior of code.

How it works

The code below has no semicolons in it, so it is up to the parser to decide where to insert them.
(function(window, undefined) {
    function test(options) {
        writeToLog('testing semicolons...!')

        (options.list || []).forEach(function(i) {

        })

        options.value.test(
            'long string to pass here',
            'and another long string to pass'
        )

        return
        {
            foo: function() {}
        }
    }
    window.test = test
})(window)
(function(window) {
    window.someLibrary = {}
})(window)
Below is the result of the parser's "guessing" game.


(function(window, undefined) {
    function test(options) {

        // Not inserted, lines got merged
        writeToLog('testing!')(options.list || []).forEach(function(i) {

        }); // <- inserted

        options.value.test(
            'long string to pass here',
            'and another long string to pass'
        ); // <- inserted

        return; // <- inserted, breaks the return statement
        { // treated as a block

            // a label and a single expression statement
            foo: function() {} 
        }; // <- inserted
    }
    window.test = test; // <- inserted
// The lines got merged again
})(window)(function(window) {
    window.someLibrary = {}; // <- inserted
})(window); //<- inserted
The parser drastically changed the behavior of the code above, in certain cases it does the wrong thing.

Leading parenthesis

In case of a leading parenthesis, the parser will not insert a semicolon.
writeToLlog('testing!')
(options.list || []).forEach(function(i) {})
This code gets transformed into one line.
writeToLog('testing!')(options.list || []).forEach(function(i) {})
Chances are very high that writeToLog does not return a function; therefore, the above will yield a TypeError stating that undefined is not a function.

Conclusion:

It is highly recommended to never omit semicolons, it is also advocated to keep braces on the same line with their corresponding statements and to never omit them for one single-line if / else statements. Both of these measures will not only improve the consistency of the code, they will also prevent the JavaScript parser from changing its behavior.

No comments:

Post a Comment

subversion video