In Firefox 3.5, I type this in the Firebug console :
false=={} // => evals to false
{}==false // syntax error
What is the explanation for this ?
In Firefox 3.5, I type this in the Firebug console :
false=={} // => evals to false
{}==false // syntax error
What is the explanation for this ?
OK, I've studied the ECMAScript specification (PDF) and I have an explanation which discuses the BNF grammar.
ECMAScript sources are parsed starting with the main symbol, called Program
:
Program:
SourceElements
SourceElements' (recursive) definition is this:
SourceElements :
SourceElement
SourceElements SourceElement
The, SourceElement is defined as:
SourceElement :
Statement
FunctionDeclaration
What we're interested in is the object literal syntax, so we ignore FunctionDeclaration and look at the Statement symbol:
Statement :
Block
VariableStatement
EmptyStatement
ExpressionStatement
IfStatement
IterationStatement
ContinueStatement
BreakStatement
ReturnStatement
WithStatement
LabelledStatement
SwitchStatement
ThrowStatement
TryStatement
I'm not sure if the listing order matters (this is how they are in the spec), but... an object literal is an ExpressionStatement, about which the standards say the following (section 12.4):
Note that an ExpressionStatement cannot start with an opening curly brace because that might make it ambiguous with a Block. Also, an ExpressionStatement cannot start with the function keyword because that might make it ambiguous with a FunctionDeclaration.
So we may have an expression at the start of the program, but it must not start with an opening curly brace ({
). That's why the following work OK:
({} == false);
alert({} == false);
!{} == false;
{
at the start of a statement signals a ‘statement block’ (see ECMA-262-3 section 12.1), which contains a list of statements.
}
immediately ends the statement block with no statements in it. That's fine. But now the parser is looking for the next statement:
==false
Huh? That's not a statement; syntax error.
What are statement blocks for? Well, you are writing a statement block every time you say:
if (something) {
...
}
JavaScript defines these flow-control statements as:
if "(" <expression> ")" <statement> [else <statement>]
ie. in the single statement form with no braces. It then allows you to use a statement-block anywhere you can use a single statement, which means you can have if-braces-many-statements. But it also means you can have a statement-block on its own with no associated flow-control statement.
This serves absolutely no practical purpose! You might be tempted to think it gave you information-hiding, but no:
var a= 1;
{
var a= 2;
}
alert(a);
...results in 2
, because statement blocks don't in themselves create a new scope.
JavaScript defines flow control and statement blocks in this manner because C (and other languages derived from it) did. Those languages didn't make {}
serve double-duty as an Object literal expression though, so they didn't have the ambiguity that makes this another JS misfeature.
Even this wannabe-literal:
{
a: 1
}
is a valid statement block, because ‘:’ is used to denote a label in a statement. (and 1
is a useless expression-statement, with the semicolon omitted.) Labels are another feature inherited from C that are rarely used in JavaScript. They're not totally pointless like the blocks, but they're seldom needed and often considered in poor taste.
(A literal with two properties will cause a syntax error, as object literals use comma separators, but labelled statements must be separated by semicolons.)
This is not the only place where JavaScript's loose syntax can trip you up by making some other statement of something you think is an expression.