区分块与对象初始值设定项

时间:2014-02-03 08:11:10

标签: javascript syntax grammar ecmascript-5

这更像是一个理论问题,而不是一个实际问题。它是关于解决由花括号分隔的一些代码。

以下是object initializers的两个例子:

f({});
({a:3})

以下是blocks的两个例子:

;{}
{a:3;}

实际上,如果先前的代码需要表达式,{...}似乎会分开一个块。

但我从来没有在ECMAScript规范中看到这样的规则明确或明显,我甚至不确定它是否属实。

某处有明确的非模棱两可的参考吗?一个正确的规则,如果这个不是吗?

1 个答案:

答案 0 :(得分:7)

  

某处是否存在明确的非模糊引用?

它遍布整个规范。

答案简短:

这取决于构造出现的上下文(这就是为什么它超出了规范)。可能它所解决的最具体的地方是§12.4,其中它表示 ExpressionStatement (在预期语句中使用的表达式)不能以{开头。< / p>

答案很长:

关键是解析器遇到{时所期望的:如果它期望一个语句,那么它知道{开始一个块。但如果它期望一个表达式,那么它知道{开始一个对象初始化器。让我们看一下作业:

doThis();   // This line is just for context
x = {a: 3};

在上面第二行的开头,解析器期待一个语句。但后来它看到x =并且知道它正在处理任务;此时,在看到=之后,解析器期待表达式语句在那里无效。所以它知道{启动一个对象初始化器,而不是块。

相反:

doThis();   // This line is just for context
{a: 3};

上面的第二行是一个包含标签声明的块。 (一个非常奇怪的一个;我们将回到那个。)解析器知道,因为在该行的开头,解析器期望一个语句,而不是一个表达式。

还有很多其他地方解析器希望看到表达式,而不是语句。例如,在属性初始值设定项中的:之后:

obj = {
    prop: {a: 3}
};

...或在进行函数调用时在参数内:

foo({a: 3});

...或者在一元运算符之后,或者在开始(之后,等等。在规范中,您可以通过语法中的解析器所说的内容来分析解析器所期望的内容。解析,例如这个语法图来自§12.5定义if语句:

 IfStatement :

if ( Expression ) Statement else Statement
if ( Expression ) Statement

这告诉我们在处理if语句时,在()解析器中需要一个表达式,但在if ()位之后,它需要一个语句。

到目前为止一直很好,但JavaScript允许(几乎)任何表达式允许的语句。这是有效的,例如:

doThis();   // This line is just for context
flag && doThat();

上面的第二行是二元逻辑运算符表达式,但是是独立的。解析器在遇到它时期待一个语句。因此,&&表达式是规范称为 ExpressionStatement 的表达式。 ExpressionStatement §12.4定义。

这让我们有些含糊不清:如果解析器期待一个语句,并且看到{,那么它是如何知道这不是作为 ExpressionStatement ExpressionStatement ExpressionStatement < EM>

答案是:通过命令。 :-)§12.4在定义 ExpressionStatement

时说明了这一点
  

注意 ExpressionStatement 不能以大括号开头,因为这可能会使 Block 模糊不清。

所以没有歧义,不是因为一些微妙的语法技巧,而是因为规范这么说。 : - )

(如果你有理由真的,真的想要将对象初始化表达式用作语句,你可以这样做;只需将它放在()中。)