JavaScript: {} == false это ошибка синтаксиса? - PullRequest
16 голосов
/ 02 октября 2009

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

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

Чем это объясняется?

Ответы [ 3 ]

41 голосов
/ 02 октября 2009
{

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

}

немедленно завершает блок операторов без операторов. Все в порядке. Но теперь парсер ищет следующее утверждение:

==false

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

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

if (something) {
    ...
}

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

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

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

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

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

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

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

Даже этот буквальный подражатель:

{
   a: 1
}

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

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

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

11 голосов
/ 02 октября 2009

ОК, я изучил спецификацию 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 не может начинаться с ключевое слово функции, потому что может сделать это двусмысленным с FunctionDeclaration.

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

  • ({} == false);
  • alert({} == false);
  • !{} == false;
0 голосов
/ 05 января 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...