何时(以及为什么)在JavaScript控制台中未定义?

时间:2012-03-29 22:21:46

标签: javascript console

在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 个答案:

答案 0 :(得分:10)

如果你自己使用花括号,它不是一个对象文字,它是一个代码块。由于代码块不包含任何代码,因此对其进行评估会产生undefined

答案 1 :(得分:6)

好的,这是我的答案。这里没有什么新东西。我只是链接到语法的ECMAScript规范(的一个漂亮的副本),并显示一些产品,以显示它解析它的方式“为什么”。在任何情况下,根据JavaScript / ECMAScript语法规则明确定义行为:{}根据其所处的“上下文”进行不同的解析。


JavaScript REPL(“控制台”)开始解析Statement语法生成或“语句上下文”中的代码。 (这实际上是一个谎言,它始于ProgramSourceElements制作,但这增加了额外的构造以便深入研究。)这是一个粗略的语法分解,简化和省略;请参阅上面的链接了解更多信息:

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,它被解析为{}; === undefinedBLOCK; BOGUS -> STMT; BOGUS,这是一个语法错误。但是,通过添加括号,此更改:({} === undefined)被解析为(EXPR === EXPR) -> (EXPR) -> EXPR -> STMT

对于{} + "hi",它被解析为{}; + "hi"BLOCK; + EXPR -> STMT; EXPR -> STMT; STMT,这是有效的语法,即使它很愚蠢(在这种情况下+是一元的) 。同样,如上所述,"hi" + {}{}置于“表达式上下文”中,并将其解析为EXPR + EXPR -> EXPR -> STMT

JavaScript控制台只是显示最后一个Statement的结果,对于空{}块,它是“未定义的”(好吧,“没有”,但不存在)。 (在这种情况下,浏览器/环境之间可能会有所不同,例如最后一个ExpressionStatement?)

快乐的编码。

答案 2 :(得分:2)

如果您只是在任何控制台中输入{}作为输入,那么除了它的位置之外,没有任何上下文可以解释您希望花括号的含义。鉴于控制台的每个输入都被解释为新的代码行,开放大括号被视为新块的开始。结束}在语法上是正确的,因为在这样的情况下经常使用空块:

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

因此{}在左侧总是未定义,并且从不吐出错误,因为空块是有效代码。

答案 3 :(得分:1)

当表达式以{开头时,似乎两个控制台都将其视为一种模糊的条件。也许它被视为一个虚拟块。

试试这个:

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

使用{}作为右手表达式可消除歧义。

您还可以从以下地址看到:

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

外括号实际上被视为虚拟块。

这似乎不是一个控制台功能。甚至eval也会这样对待他们,暗示你在控制台中输入的内容实际上的评估方式与传递给eval的方式相同:

eval("{}") // undefined
eval("{alert(42)}") // alerts 42

答案 4 :(得分:0)

问题在于,在某些情况下,javascript会将{和}视为打开和关闭/ block /。而在其他情况下,{}是一个对象。案件确实取决于具体情况。

答案 5 :(得分:0)

Doug Crockford抱怨这个。你到达那个WTF是由于+运营商本身。它既用于算术又用于连接。在你的最后一行,你看到+运算符将undefined和空对象转换为字符串,并将它们连接起来。

答案 6 :(得分:0)

Javascript将语句和表达式的概念分开(C ++或Java等语言也是如此)。

例如if ...是一个语句,x?y:z是一个表达式。

表达式有值,声明没有。

Javascript语法的一个问题是{}可以是表达式(在这种情况下,它表示空对象构造函数)或语句(在这种情况下,它表示空代码块...基本上一个NOP)所以如何解释它取决于上下文。