Well, first I should probably ask if this is browser dependent.
I've read that if an invalid token is found, but the section of code is valid until that invalid token, a semicolon is inserted before the token if it is preceded by a line break.
However, the common example cited for bugs caused by semicolon insertion is:
return _a+b;
..which doesn't seem to follow this rule, since _a would be a valid token.
On the other hand, breaking up call chains works as expected:
$('#myButton') .click(function(){alert("Hello!")});
Does anyone have a more in-depth description of the rules?
Automatic Semicolon Insertion (ASI) Unlike other C-like languages, JavaScript does not enforce the use of a semicolon at the end of a statement. Instead, the semicolon is optional, and the JavaScript interpreter will "intelligently" add them when it runs the code.
Semicolons are an essential part of JavaScript code. They are read and used by the compiler to distinguish between separate statements so that statements do not leak into other parts of the code.
To recap, semicolons are not mandatory in JavaScript. Instead, the Automatic Semicolon Insertion (ASI) process adds semicolons where necessary. However the ASI is not correct 100% of the time. Also, in some situations, you simply have to use a semicolon.
I could not understand those 3 rules in the specs too well -- hope to have something that is more plain English -- but here is what I gathered from JavaScript: The Definitive Guide, 6th Edition, David Flanagan, O'Reilly, 2011:
Quote:
JavaScript does not treat every line break as a semicolon: it usually treats line breaks as semicolons only if it can’t parse the code without the semicolons.
Another quote: for the code
var a a = 3 console.log(a)
JavaScript does not treat the second line break as a semicolon because it can continue parsing the longer statement a = 3;
and:
two exceptions to the general rule that JavaScript interprets line breaks as semicolons when it cannot parse the second line as a continuation of the statement on the first line. The first exception involves the return, break, and continue statements
... If a line break appears after any of these words ... JavaScript will always interpret that line break as a semicolon.
... The second exception involves the ++ and −− operators ... If you want to use either of these operators as postfix operators, they must appear on the same line as the expression they apply to. Otherwise, the line break will be treated as a semicolon, and the ++ or -- will be parsed as a prefix operator applied to the code that follows. Consider this code, for example:
x ++ y
It is parsed as
x; ++y;
, not asx++; y
So I think to simplify it, that means:
In general, JavaScript will treat it as continuation of code as long as it makes sense -- except 2 cases: (1) after some keywords like return
, break
, continue
, and (2) if it sees ++
or --
on a new line, then it will add the ;
at the end of the previous line.
The part about "treat it as continuation of code as long as it makes sense" makes it feel like regular expression's greedy matching.
With the above said, that means for return
with a line break, the JavaScript interpreter will insert a ;
(quoted again: If a line break appears after any of these words [such as return
] ... JavaScript will always interpret that line break as a semicolon)
and due to this reason, the classic example of
return { foo: 1 }
will not work as expected, because the JavaScript interpreter will treat it as:
return; // returning nothing { foo: 1 }
There has to be no line-break immediately after the return
:
return { foo: 1 }
for it to work properly. And you may insert a ;
yourself if you were to follow the rule of using a ;
after any statement:
return { foo: 1 };
First of all you should know which statements are affected by the automatic semicolon insertion (also known as ASI for brevity):
var
statementdo-while
statementcontinue
statementbreak
statementreturn
statementthrow
statementThe concrete rules of ASI, are described in the specification §11.9.1 Rules of Automatic Semicolon Insertion
Three cases are described:
LineTerminator
.}
e.g.:
{ 1 2 } 3
is transformed to
{ 1 ;2 ;} 3;
The NumericLiteral
1
meets the first condition, the following token is a line terminator.
The 2
meets the second condition, the following token is }
.
e.g.:
a = b ++c
is transformed to:
a = b; ++c;
Restricted productions:
UpdateExpression : LeftHandSideExpression [no LineTerminator here] ++ LeftHandSideExpression [no LineTerminator here] -- ContinueStatement : continue ; continue [no LineTerminator here] LabelIdentifier ; BreakStatement : break ; break [no LineTerminator here] LabelIdentifier ; ReturnStatement : return ; return [no LineTerminator here] Expression ; ThrowStatement : throw [no LineTerminator here] Expression ; ArrowFunction : ArrowParameters [no LineTerminator here] => ConciseBody YieldExpression : yield [no LineTerminator here] * AssignmentExpression yield [no LineTerminator here] AssignmentExpression
The classic example, with the ReturnStatement
:
return "something";
is transformed to
return; "something";
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With