JavaScript: {}==false is a SyntaxError?

蹲街弑〆低调 提交于 2019-11-28 06:56:06
bobince
{

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.

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;

Simply to say, {}==false are compiled by Js compiler to {};==false, so it's syntax error. you should write ({})==false and it'll return false.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!