В Firefox 3.5 я набираю это в консоли Firebug:
false=={} // => evals to false
{}==false // syntax error
Каково объяснение этого?
В Firefox 3.5 я набираю это в консоли Firebug:
false=={} // => evals to false
{}==false // syntax error
Каково объяснение этого?
{
в начале выражения сигнализирует "блок оператора" (см. 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-синтаксис может вас пошевелить, сделав какое-то другое утверждение того, что, по вашему мнению, является выражением.
ОК, я изучил спецификацию 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;
Просто сказать, {}==false
скомпилированы компилятором Js на {};==false
, поэтому он синтаксическая ошибка. вы должны написать ({})==false
, и он вернет false.