Когда (и почему) {} не определено в консоли JavaScript? - PullRequest
9 голосов
/ 30 марта 2012

В консоли как FF, так и Chrome {} считается неопределенной до явной оценки:

{};     // undefined
({});   // ▶ Object

На самом деле, он немного менее определен, чем неопределенный - это явно плохой синтаксис:

{} === undefined;  // SyntaxError: Unexpected token ===
{}.constructor;    // SyntaxError: Unexpected token .

Но нет, если он на другой стороне, в этом случае все в порядке:

"[object Object]" == {}.toString(); // true

Или, если это не первое выражение:

undefined + undefined; // NaN
{} + undefined;        // NaN
undefined + {};        // "undefined[object Object]"

Что дает?

Ответы [ 7 ]

10 голосов
/ 30 марта 2012

Если вы используете фигурные скобки сами по себе, это не объектный литерал, а блок кода. Поскольку блок кода не содержит кода, его оценка приводит к undefined.

6 голосов
/ 30 марта 2012

Хорошо, вот мой ответ. Здесь нет ничего нового. Я просто ссылаюсь на (симпатичную копию) спецификации ECMAScript для грамматики и показываю несколько произведений, чтобы показать, «почему» она анализирует так, как это делает. В любом случае, поведение четко определено в соответствии с правилами грамматики JavaScript / ECMAScript: {} анализируется по-разному в зависимости от "контекста", в котором он находится.


JavaScript REPL s («консоли») начинает анализировать код в Statement грамматическом производстве или «контексте оператора». (На самом деле это ложь, она начинается с производства Program или SourceElements, но это добавляет дополнительные конструкции, чтобы копаться в них.) Вот грубая грамматическая разбивка с упрощениями и упущениями; см. ссылку выше для получения дополнительной информации:

Statement
    Block
    ...
    ExpressionStatement

Block
    # This is actually { StatementList[optional] }, but this is what
    # it amounts to: * means "0 or more".
    { Statement* }

ExpressionStatement
    # An ExpressionStatement can't start with "{" or "function" as
    # "{" starts a Block and "function" starts a FunctionStatement.
    [lookahead ∉ {{, function}]Expression ;

Expression
    # This is really PrimaryExpression; I skipped a few steps.
    ...
    ( Expression )

Таким образом (в «контексте оператора»):

   {}
-> Block  # with no StatementList (or "0 statements")
-> Statement

И

   ({})
-> (Expression)
-> Expression
-> ExpressionStatement  # omitted in productions below
-> Statement

Это также объясняет, почему undefined === {} анализируется как EXPR === EXPR -> EXPR -> STMT и приводит к ложному при оценке. {} в этом случае находится в «контексте выражения».

В случае {} === undefined он анализируется как {}; === undefined или BLOCK; BOGUS -> STMT; BOGUS, что является синтаксической ошибкой. Однако с добавлением скобок это меняется: ({} === undefined) анализируется как (EXPR === EXPR) -> (EXPR) -> EXPR -> STMT.

В случае {} + "hi" он анализируется как {}; + "hi" или BLOCK; + EXPR -> STMT; EXPR -> STMT; STMT, что является допустимым синтаксисом, даже если он глупый (+ в данном случае унарный). Аналогично, как и выше, "hi" + {} помещает {} в "контекст выражения" и анализируется как EXPR + EXPR -> EXPR -> STMT.

Консоль JavaScript просто показывает результат последнего оператора, который является «неопределенным» (ну, на самом деле, «ничем», но его не существует) для пустого блока {}. (Это может варьироваться в зависимости от браузера / среды относительно того, что возвращается в этом случае, например, только последнее ExpressionStatement?)

Удачного кодирования.

2 голосов
/ 30 марта 2012

Если вы просто наберете {} в качестве ввода в любой консоли, нет контекста для интерпретации значения фигурных скобок, кроме его положения.учитывая тот факт, что каждый ввод в консоль интерпретируется как новая строка кода, открывающая фигурная скобка рассматривается как начало нового блока.Закрытие } является синтаксически правильным, поскольку пустой блок часто используется в ситуациях, подобных этим:

try
{
    //something
}
catch(e)
{}//suppress error

Следовательно, {} всегда будет неопределенным, если он находится слева, и никогда не плюетсяошибки в виде пустого блока является допустимым кодом.

1 голос
/ 30 марта 2012

Кажется, что обе консоли рассматривают его как неоднозначное условие, когда выражение начинается с {.Возможно, он рассматривается как фиктивный блок.

Попробуйте это:

{} // undefined
undefined === {} // false

Использование {} в качестве выражения правой руки устраняет неоднозначность.

Также выиз:

{a:42} // 42
{{a:42}} // 42
{{{a:42}}} // 42

видно, что внешние скобки действительно рассматриваются как фиктивный блок.

И это не похоже на консольную функцию.Даже eval относится к ним так, намекая на то, что текст, который вы вводите в консоль, действительно оценивается так же, как при передаче на eval:

eval("{}") // undefined
eval("{alert(42)}") // alerts 42
0 голосов
/ 30 марта 2012

Javascript разделяет концепцию операторов и выражений (языки, такие как C ++ или Java, делают то же самое).

Например, if ... - это оператор, а x?y:z - это выражение.

У выражений есть значение, у операторов - нет.

Одна проблема с синтаксисом Javascript заключается в том, что {} может быть либо выражением (а в данном случае это означает пустой конструктор объекта), либо выражением (и в этомесли это означает пустой блок кода ... в основном NOP), то как его интерпретировать, зависит от контекста.

0 голосов
/ 30 марта 2012

Даг Крокфорд жалуется на это.Тот WTF, который вы получаете, связан с самим оператором +.Он используется как для арифметики и объединения.В последней строке вы видите, что оператор + преобразует неопределенный и пустой объект в строки и объединяет их.

0 голосов
/ 30 марта 2012

Проблема в том, что в некоторых случаях javascript видит {и} как открывающий и закрывающий / block /.В то время как в других случаях {} является объектом.Случаи действительно зависят от контекста.

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