难以理解分号插入

3
根据这里所述,如果JavaScript程序包含一个不符合正式语法规则的标记,那么会在该位置插入分号,如果(a)在该位置有换行符,或者(b)意外的标记是闭括号。经典的例子是:
return  //  <--- semicolon inserted there
{
   id: 12
};

这使我相信单独的 { 不是有效的。但是下面这段(无意义的)代码会弹出 2,没有错误。
function foo() {
    var x = 1;
    {
        var y = 2; //yes, I know y has the same scope as x 
    }              //and that this is therefore pointless
    alert(y);
}

为什么在第一段代码中左花括号被视为无效标记,导致JavaScript插入分号,但是在第二个代码中左花括号不被视为无效标记,这表明没有错误发生。
显然我的其中一个假设是错误的,我希望有人能帮助我理解哪个是错的。
3个回答

5
你提到的return语句问题与分号插入规则的特定方面无关。实际上,是由以下规则引起的:
当程序从左到右解析时,遇到某个标记,该标记允许文法的某些产生式,但该产生式是一个受限制的产生式,并且该标记将是立即跟在注释“[no LineTerminator here]”后面的终结符或非终结符的第一个标记(因此称这样的标记为受限制的标记),并且受限制的标记与前一个标记至少间隔了一个LineTerminator,则会在受限制的标记之前自动插入分号。
恰巧,return语句语法具有其中一个“[no LineTerminator here]”的怪癖。
请参见ES 5规范的第7.9.1节。

我谦卑地道歉,因为我之前的回答中有一个不太正确的版本,偷了一个赞。但是我认为上面的回答是正确的。 - Pointy
1
据我所知,在Javascript中,仅使用return是完全有效的,它将返回undefined - Peter
@Pointy - 感谢您挖掘出规范的那一部分。所以我猜您已经使用JavaScript超过一两年了... - Adam Rackis
@Peter: "......它只会返回undefined" 是的,正如第12.9节所述。在“没有区别的区别”类别中,技术上,显式return;和执行到函数结尾(隐式返回)之间存在差异。在隐式情况下,函数不返回任何东西--但是函数调用表达式然后处理它就像return;return undefined;一样(第13.2.1节)。</geekSilliness> - T.J. Crowder

2
这个规则是这样的:如果有一个新行,而且我们到目前为止有一个有效的语句,那么就插入一个分号。
在你的第一个例子中,这是有效的:
return;  //  <--- semicolon inserted there
{
   id: 12
};

在第二个例子中,这是无效的:
function foo() {
    var x = 1;
    {;             // *not a valid insertion*
        var y = 2; // yes, I know y has the same scope as x 
    }              // and that this is therefore pointless
    alert(y);
}

编辑:这个答案并不完全正确!例如:

num = 4 + 5
  + 1;

// returns 10

请看下方评论:


这并不完全是规则。 - Pointy
@Pointy 这基本上是规则的要点,你能给我展示一个反例吗? - Peter
那不是规则。反例:var x = 1 + 2 [newline] + 3 [newline] + 4; 第二个反例:var x = document [newline] .getElementById("x1"); - nnnnnn
@nnnnnn 谢谢。很好。所以我想这归结于知道哪些标记是受限制的。我想这就是为什么应该避免使用分号插入的原因。 :) - Peter
我认为一个合理的普通英语概括是,对于return和throw语句,会插入一个分号,但如果下一行作为当前行的延续是有意义的,则不会插入分号。(我不会感到惊讶如果var语句也是这样工作的,但我懒得查 - 而且我认为既然我说了“概括”,那就没关系了。可以说return和throw是最有可能在它们之后出现错误换行的两个语句。) - nnnnnn

0
你在谈论期望块和期望表达式的关键字 - return 不像期望块 ({ }) 的 functionif,所以解析器会像其他不期望大括号的关键字一样插入分号。

如果你要返回一个对象字面量,用花括号是可以的。 - Pointy
我并不是说花括号不好,但如果解析器不期望它,它就不会在下一行查找 - 如果你在下一行(们)有对象键/值,那就很酷了 - 或者像赋值运算符一样,var foo = 可以在第一行,{ bar: 'baz' } 可以在下一行。 - Dan Heberden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接