自动分号插入和返回语句

正如你可能知道的那样,ECMAscript试图变得聪明,如果你没有明确地写入分号 ,它会自动插入分号 。 简单的例子

function foo() { var bar = 5 return bar } 

仍然按预期工作。 但是,如果你依赖于这一点,有一些警告。 如果我们重新写这样的function

 function foo() { var bar = 5 return { bar: bar } } 

..这个函数现在会返回undefined因为解释器会在return语句后面插入这个分号(这就是为什么你总是应该在同一行作为一个语句带上大括号的原因)。

但是,知道所有这一切,我想知道现在在不同的浏览器和版本中,像下面这样的return语句是多么的安全

 function foo() { var a = true, b = true, c = false; return a && b && c; } 

我只是在生产环境中写了一个类似的return statement 。 只是因为我知道ECMAscript的“问题”,如果不是那么聪明的分号插入,我现在想知道,如果该代码工作100%。 在我的FF / Chrome / IE(最新版本)的第一次testing中,这似乎是完全正确的,但它是真的吗?

自动分号插入是否“唤醒”,如果有其他什么,但在该行中的return语句? 任何人都可以提供有关此实现级别的细节?

JavaScript解释器/编译器是如此聪明,只有插入自动分号,如果以后有有效的Javascript。

你的代码是有效的,因为&& b就像没有有效的expression式 – 这就是为什么在return a后没有插入分号导致:

 return a && b && c; 

然而:

 return (undefined);//implicitely inserted { .... } 

是完全有效的,这就是为什么插入分号。

为了完整起见,参考spec: 自动分号插入 。 这些例子值得一读。

不特定的浏览器/实现,但是Section 7.9 Automatic Semicolon Insertion ECMAScript语言规范是值得一读的。

7.9自动分号插入

某些ECMAScript语句(空语句,variables语句,expression式语句,do-while语句,continue语句,break语句,return语句和throw语句)必须以分号结尾。 这样的分号可能总是显示在源文本中。 但是,为了方便起见,在某些情况下可能会从源文本中省略这些分号。 这些情况通过在这些情况下将分号自动插入源代码标记stream来描述。

7.9.1自动插入分号的规则分号插入有三个基本规则:

  1. 当从左向右parsing程序时,会遇到任何语法产生都不允许的令牌(称为违规令牌),那么在冒犯令牌之前会自动插入分号,如果一个或多个以下条件是正确的:

    • 有问题的令牌至less由一个LineTerminator与前一个令牌分开。
    • 有罪的令牌是}。
  2. 当从左到右分析程序时,会遇到令牌inputstream的结束,并且parsing器无法将input令牌streamparsing为单个完整的ECMAScript程序,则在分配结束时会自动插入分号inputstream。

  3. 当程序从左到右被parsing时,会遇到某个语法生成所允许的令牌,但是生产是一个受限制的生产,并且该令牌将是紧跟在注释之后的terminal或非terminal的第一个令牌?[这里没有LineTerminator]? 在受限制的生产中(因此这样的一个标记被称为受限制的标记),并且受限制的标记与前一个标记由至less一个LineTerminator分开,然后在受限制的标记之前自动插入分号。 但是,对于上述规则,还有一个额外的重载条件:如果分号将被parsing为空语句,或者该分号将成为for语句头中的两个分号之一,则从不自动插入分号(请参见12.6.3)。 注意以下是语法中唯一受限制的生成:PostfixExpression:LeftHandSideExpression [no LineTerminator here] ++ LeftHandSideExpression [no LineTerminator here] – ContinueStatement:continue [no LineTerminator here]标识符; BreakStatement:break [no LineTerminator here]标识符; ReturnStatement:return [no LineTerminator here]expression式; ThrowStatement:抛出[在这里没有LineTerminator]expression式; 这些受限制的产品的实际效果如下所示:当遇到++或 – 标记时,parsing器会将其视为后缀运算符,并且在前一个标记与++或 – 令牌之间至less出现一个LineTerminator ,那么在++或 – 令牌之前自动插入一个分号。 遇到continue,break,return或throw标记,并在下一个标记之前遇到LineTerminator时,会在continue,break,return或throw标记之后自动插入分号。 由此产生的对ECMAScript程序员的实际build议是:后缀++或 – 操作符应该出现在它的操作数的同一行上。 返回或抛出语句中的expression式应该与返回或抛出令牌在同一行上开始。 break或continue语句中的标识符应该与break或continue标记位于同一行。

7.9.2自动分号插入示例

来源

 { 1 2 } 3 

在ECMAScript语法中不是有效的句子,即使使用自动分号插入规则。 相反,来源

 { 1 2 } 3 

也不是一个有效的ECMAScript句子,而是通过自动分号插入转换为以下内容:

 { 1 ;2 ;} 3; 

这是一个有效的ECMAScript句子。 来源

 for (a; b ) 

不是有效的ECMAScript句子,并且不会被自动分号插入更改,因为for语句的标头需要分号。 自动分号插入从不在for语句的标题中插入两个分号之一。 来源

 return a + b 

通过自动分号插入转换为以下内容:

 return; a + b; 

注:expression式a + b不被视为由return语句返回的值,因为LineTerminator将它从令牌返回中分离出来。 来源

 a = b ++c 

通过自动分号插入转换为以下内容:

 a = b; ++c; 

注:由于LineTerminator发生在b和++之间,所以令牌++不被视为应用于variablesb的后缀运算符。 来源

 if (a > b) else c = d 

不是一个有效的ECMAScript语句,并且在else标记之前不会被自动分号插入所改变,即使此时没有生成语法,因为自动插入的分号会被parsing为空语句。 来源

 a = b + c (d + e).print() 

不会被自动分号插入转换,因为开始第二行的括号expression式可以被解释为函数调用的参数列表:

 a = b + c(d + e).print() 

在赋值语句必须以左括号开始的情况下,程序员在前面的语句末尾提供一个明确的分号是一个好主意,而不是依靠自动分号插入。

正如Christoph指出的那样,您的退货声明将在所有浏览器中正确运行。 我更喜欢使它更加明确,如果不是为了计算机,而是为了人类,至less要以不同的方式放置运算符:

 return a && b && c; 

在这种情况下,没有人需要花一秒钟的时间思考自动分号是否会造成严重破坏。 我只喜欢这个JavaScript,你的原始代码更容易阅读。