JavaScript: {} == false - это SyntaxError?

В Firefox 3.5 я набираю это в консоли Firebug:

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

Каково объяснение этого?

Ответ 1

{

в начале выражения сигнализирует "блок оператора" (см. ECMA-262-3, раздел 12.1), который содержит список заявления.

}

немедленно завершает блок оператора без каких-либо утверждений. Это здорово. Но теперь синтаксический анализатор ищет следующее утверждение:

==false

А? Это не утверждение; синтаксическая ошибка.

Что представляют собой блоки операторов? Ну, вы пишете блок утверждения каждый раз, когда вы говорите:

if (something) {
    ...
}

JavaScript определяет эти операторы управления потоком как:

if "(" <expression> ")" <statement> [else <statement>]

т. в одной форме заявления без брекетов. Затем он позволяет использовать блок-оператор в любом месте, где вы можете использовать один оператор, что означает, что вы можете иметь if-braces-many-statements. Но это также означает, что вы можете иметь блок-блок самостоятельно, без соответствующего оператора управления потоком.

Это не имеет практической цели! Возможно, у вас возникнет соблазн подумать, что он скрывает информацию, но нет:

var a= 1;
{
    var a= 2;
}
alert(a);

... приводит к 2, потому что блоки операторов сами по себе не создают новую область.

JavaScript определяет блоки управления потоками и операторы таким образом, потому что C (и другие языки, полученные из него). Эти языки не делали {} двойным делом как выражение объекта Object, хотя они не имели двусмысленности, которая делает эту еще одну неудачную JS-ошибку.

Даже этот wannabe-literal:

{
   a: 1
}

является допустимым блоком оператора, потому что ': используется для обозначения метки в инструкции. (и 1 - бесполезный оператор выражения, при этом точка с запятой опущена.) Ярлыки - это еще одна функция, унаследованная от C, которые редко используются в JavaScript. Они не совсем бессмысленны, как блоки, но они редко нужны и часто считаются со слабым вкусом.

(Литерал с двумя свойствами вызовет синтаксическую ошибку, поскольку литералы объектов используют разделители запятой, но помеченные операторы должны быть разделены точкой с запятой.)

Это не единственное место, где JavaScript-синтаксис может вас пошевелить, сделав какое-то другое утверждение того, что, по вашему мнению, является выражением.

Ответ 2

ОК, я изучил спецификацию ECMAScript (PDF), и у меня есть объяснение, в котором описывается BNF-грамматика.

Источники ECMAScript анализируются начиная с основного символа, называемого Program:

Program:
    SourceElements

Определение SourceElements (рекурсивное):

SourceElements :
    SourceElement
    SourceElements SourceElement

Элемент SourceElement определяется как:

SourceElement :
    Statement
    FunctionDeclaration

Нам интересен синтаксис литерала объекта, поэтому мы игнорируем FunctionDeclaration и смотрим на символ Statement:

Statement :
    Block
    VariableStatement
    EmptyStatement
    ExpressionStatement
    IfStatement
    IterationStatement
    ContinueStatement
    BreakStatement
    ReturnStatement
    WithStatement
    LabelledStatement
    SwitchStatement
    ThrowStatement
    TryStatement

Я не уверен, что вопрос о листинге имеет значение (так оно и есть в спецификации), но... литерал объекта - это выражение ExpressionStatement, о котором стандарты говорят следующее (раздел 12.4):

Обратите внимание, что выражение ExpressionStatement не может начинаться с открытия курчавого скобки, потому что это может сделать это неоднозначный с блоком. Кроме того, ExpressionStatement не может начинаться с ключевое слово function, поскольку может сделать его двусмысленным с FunctionDeclaration.

Таким образом, мы можем иметь выражение в начале программы, но оно не должно начинаться с открывающей фигурной скобки ({). Вот почему следующая работа ОК:

  • ({} == false);
  • alert({} == false);
  • !{} == false;

Ответ 3

Просто сказать, {}==false скомпилированы компилятором Js на {};==false, поэтому он синтаксическая ошибка. вы должны написать ({})==false, и он вернет false.