views:

428

answers:

2

In Firefox 3.5, I type this in the Firebug console :

false=={} // => evals to false
{}==false // syntax error

What is the explanation for this ?

+8  A: 

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;
Ionuț G. Stan
-1 Is not a real answer (.. or perhaps I'm just not getting your point). Feel free to enlighten me :)
roosteronacid
You're totally right. Is rather a workaround. I'm searching through the ECMAScript 3 specification in order to find the real answer. I'm curious myself too.
Ionuț G. Stan
Aye. I undid my down vote.
roosteronacid
+24  A: 
{

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.

bobince
And ({}) == false works.
Ates Goral
Yes, and !{}==true also works !
subtenante
yes and egg !== beetroot is also false, because you can beat and egg but you can't beat a root.
Evernoob
Indeed, anything that stops the parser seeing `{` at the start of the statement will revert to the expected expression-statement.
bobince