将块与对象初始化程序区分开 [英] Differentiate a block from an object initializer

查看:93
本文介绍了将块与对象初始化程序区分开的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个理论问题,而不是实际问题。

This is more a theoretical question than a practical one. It's about the parsing of some code delimited by curly braces.

这里是对象初始化程序

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

以下是

;{}
{a:3;}

在实践中,似乎 {...} 如果先验代码需要表达式则分开一个块。

In practice, it seems that {...} makes a block apart if the precedent code requires an expression.

但是我从未见过这样的规则在ECMAScript规范中是明确的或显而易见的,我什至不确定它是真的。

But I've never seen such a rule explicit or made obvious in the ECMAScript specification and I'm not even sure it's true.

在某处是否存在明确的非歧义引用?

Is there a definitive non ambiguous reference somewhere ? A correct rule if this one isn't ?

推荐答案


在某处是否存在明确的非歧义引用?

Is there a definitive non ambiguous reference somewhere ?

某种程度上遍布整个规范。

It's sort of spread all over the spec.

简称答案:

这取决于构造出现的上下文(这就是为什么在整个规范中都如此)。可能解决的最具体的地方是§12.4,其中它表示 ExpressionStatement (用于在需要声明的位置使用的表达式)不能以 {

It depends on the context where the construct appears (which is why it's all over the spec). Probably the most specific place it's addressed is §12.4, where it says that an ExpressionStatement (an expression used where a statement is expected) can't start with a {.

长答案:

关键是解析器在遇到 {:如果期望语句,则知道 {开始一个块。但是,如果期望表达式,则知道 {开始一个对象初始化器。让我们看一下分配:

The key is what the parser is expecting when it encounters the {: If it's expecting a statement, then it knows the { begins a block. But if it's expecting an expression, then it knows the { begins an object initializer. Let's look at an assignment:

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

在上面第二行的开头,解析器期待一个语句。但随后看到 x = 并知道它正在处理分配;那时,解析器在看到 = 之后,期望的是表达式声明在那里无效。因此,它知道 {启动一个对象初始化程序,而不是一个块。

At the beginning of the second line above, the parser is expecting a statement. But then it sees the x = and knows it's handling an assignment; at that point, after seeing the =, the parser is expecting an expression. A statement is invalid there. So it knows the { starts an object initializer, not a block.

相反:

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

上面的第二行是包含标记语句的块。 (一个看起来很奇怪的代码;我们将回到这一点。)解析器知道,因为在该行的开头,解析器期望的是语句,而不是表达式。

The second line above is a block containing a labelled statement. (A very odd-looking one; we'll come back to that.) The parser knows that because at the beginning of that line, the parser is expecting a statement, not an expression.

解析器希望在其他许多地方看到表达式,而不是语句。例如,在属性初始化器中的之后:

There are lots of other places where the parser expects to see expressions, not statements. For instance, after the : in a property initializer:

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

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

...or within the arguments when doing a function call:

foo({a: 3});

...或者在一元运算符之后,或者刚好在之后,等等。在规范中,您可以通过语法中对解析器进行解析的内容来告诉解析器期望什么,例如,来自§12.5定义 if 语句:

...or after a unary operator, or just after an opening (, etc. In the spec, you can tell what the parser will be expecting by what it says in the grammar for what the parser is parsing, e.g. this syntax diagram from §12.5 defining the if statement:

 IfStatement :

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

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

That tells us that when handling an if statement, within the () the parser expects an expression, but after the if () bit, it expects a statement.

到目前为止还不错,但是JavaScript允许(几乎)任何允许执行语句的表达式,这是有效的,例如:

So far so good, but JavaScript allows (almost) any expression wherever a statement is allowed. This is valid, for instance:

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

上面的第二行是二进制逻辑运算符表达式,但具有独立性。解析器在遇到语句时期望它。因此,& 表达式是规范称为的 ExpressionStatement ExpressionStatement §12.4。

The second line above is a binary logical operator expression, but freestanding. The parser was expecting a statement when it encountered it. So the && expression is what the spec calls an ExpressionStatement. ExpressionStatement is defined by §12.4.

所以这给我们留下了一些歧义:如果解析器期望一个语句,并且看到 { ,它怎么知道不是对象初始化程序表达式的开始充当 ExpressionStatement

So that leaves us with some ambiguity: If the parser is expecting a statement, and sees a {, how does it know that's not the beginning of an object initializer expression acting as an ExpressionStatement?

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

The answer is: By fiat. :-) §12.4 says this when defining ExpressionStatement:


注意An ExpressionStatement 不能以花括号开头,因为这可能会使它与 Block 产生歧义。

NOTE An ExpressionStatement cannot start with an opening curly brace because that might make it ambiguous with a Block.

所以没有模棱两可,这并不是因为语法上的一些技巧,而是因为规范中是这样说的。 :-)

So there's no ambiguity, not because of some subtle syntax trick, but just because the spec says so. :-)

(如果您确实有理由真的想使用对象初始值设定项表达式作为语句,则可以这样做;只需将其放在<$之内c $ c>()。)

(If you had a reason for really, really wanting to use an object initializer expression as a statement, you can do it; just put it within ().)

这篇关于将块与对象初始化程序区分开的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆