T.R*_*.R. 400 javascript automatic-semicolon-insertion
好吧,首先我应该问一下这是否依赖于浏览器.
我已经读过,如果找到一个无效的令牌,但代码段在该无效令牌之前有效,则在令牌之前插入分号(如果前面有换行符).
但是,由分号插入引起的错误引用的常见示例是:
return
_a+b;
Run Code Online (Sandbox Code Playgroud)
..它似乎不遵循这个规则,因为_a将是一个有效的标记.
另一方面,分解调用链按预期工作:
$('#myButton')
.click(function(){alert("Hello!")});
Run Code Online (Sandbox Code Playgroud)
有没有人对规则有更深入的描述?
CMS*_*CMS 420
首先,您应该知道哪些语句受自动分号插入影响(为简洁起见,也称为ASI):
var 声明do-while 声明continue 声明break 声明return 声明throw 声明ASI的具体规则在规范§11.9.1自动分号插入规则中有所描述
描述了三种情况:
当遇到语法不允许的令牌(LineTerminator或})时,如果出现以下情况,则会在其前面插入分号:
LineTerminator.}例如:
{ 1
2 } 3
Run Code Online (Sandbox Code Playgroud)
变成了
{ 1
;2 ;} 3;
Run Code Online (Sandbox Code Playgroud)
在NumericLiteral 1满足所述第一条件,下面令牌是一个行结束.
在2满足第二条件,下面令牌}.
当遇到令牌输入流的末尾并且解析器无法将输入令牌流解析为单个完整程序时,则在输入流的末尾自动插入分号.
例如:
a = b
++c
Run Code Online (Sandbox Code Playgroud)
转变为:
a = b;
++c;
Run Code Online (Sandbox Code Playgroud)这种情况发生在某些语法生成允许令牌的情况下,但是生产是限制生产,在限制令牌之前自动插入分号.
限制作品:
UpdateExpression :
LeftHandSideExpression [no LineTerminator here] ++
LeftHandSideExpression [no LineTerminator here] --
ContinueStatement :
continue ;
continue [no LineTerminator here] LabelIdentifier ;
BreakStatement :
break ;
break [no LineTerminator here] LabelIdentifier ;
ReturnStatement :
return ;
return [no LineTerminator here] Expression ;
ThrowStatement :
throw [no LineTerminator here] Expression ;
ArrowFunction :
ArrowParameters [no LineTerminator here] => ConciseBody
YieldExpression :
yield [no LineTerminator here] * AssignmentExpression
yield [no LineTerminator here] AssignmentExpression
Run Code Online (Sandbox Code Playgroud)
经典的例子,有ReturnStatement:
return
"something";
Run Code Online (Sandbox Code Playgroud)
变成了
return;
"something";
Run Code Online (Sandbox Code Playgroud)Jör*_*tag 41
7.9.1自动分号插入规则
分号插入有三个基本规则:
- 当从左到右解析程序时,遇到任何语法生成不允许的令牌(称为违规令牌),如果出现以下一个或多个,则在违规令牌之前自动插入分号条件是真的:
- 违规令牌与先前令牌分开至少一个
LineTerminator.- 令人不快的令牌是}.
- 当从左到右解析程序时,遇到令牌输入流的末尾,并且解析器无法将输入令牌流解析为单个完整的ECMAScript
Program,然后在结束时自动插入分号.输入流.- 当从左到右解析程序时,会遇到某些语法生成所允许的令牌,但是生产是限制生产,并且令牌将是紧跟注释后的终端或非终端的第一个令牌限制生产中的" [no
LineTerminatorhere] "(因此这种令牌称为受限令牌),并且受限令牌通过至少一个LineTerminator与前一令牌分开,然后在受限令牌之前自动插入分号.但是,前面的规则还有一个额外的重要条件:如果分号将被解析为空语句,或者如果该分号将成为for语句标题中的两个分号之一,则永远不会自动插入分号(参见12.6) 0.3).
nop*_*ole 35
我无法理解规范中的这3条规则 - 希望有更简单的英语 - 但这是我从JavaScript中收集到的:The Definitive Guide,第6版,David Flanagan,O'Reilly,2011:
引用:
JavaScript不会将每个换行符视为分号:只有在没有分号的情况下才能解析代码时,它通常将换行符视为分号.
另一个引用:代码
var a
a
=
3 console.log(a)
Run Code Online (Sandbox Code Playgroud)
JavaScript不会将第二个换行符视为分号,因为它可以继续解析较长的语句a = 3;
和:
一般规则的两个例外,当JavaScript无法将第二行解析为第一行语句的延续时,JavaScript将换行符解释为分号.第一个例外涉及return,break和continue语句
...如果在任何这些单词之后出现换行符...... JavaScript将始终将该换行符解释为分号.
...第二个例外涉及++和 - 运算符......如果要将这些运算符中的任何一个用作后缀运算符,它们必须与它们应用的表达式出现在同一行.否则,换行符将被视为分号,++或 - 将被解析为应用于后面的代码的前缀运算符.考虑这段代码,例如:
x
++
y
Run Code Online (Sandbox Code Playgroud)
它被解析为
x; ++y;,而不是x++; y
所以我想简化它,这意味着:
在一般情况下,用JavaScript,只要它是有意义把它当作代码延续-除了两种情况:(1)像一些关键字后return,break,continue,和(2)如果看到++或者--在新的一行,则反而会加重该;在前一行的末尾.
关于"将其视为代码的延续,只要它有意义"的部分使得它感觉像正则表达式的贪婪匹配.
如上所述,这意味着对于return换行符,JavaScript解释器将插入一个;
(再次引用:如果在任何这些单词之后出现换行符[例如return] ...... JavaScript将始终将该换行符解释为分号)
并且由于这个原因,经典的例子
return
{
foo: 1
}
Run Code Online (Sandbox Code Playgroud)
将无法正常工作,因为JavaScript解释器会将其视为:
return; // returning nothing
{
foo: 1
}
Run Code Online (Sandbox Code Playgroud)
在return:之后必须立即没有换行符:
return {
foo: 1
}
Run Code Online (Sandbox Code Playgroud)
为了它正常工作.;如果您遵循使用;后任何声明的规则,您可以插入自己:
return {
foo: 1
};
Run Code Online (Sandbox Code Playgroud)
Geo*_*pty 17
关于分号插入和var语句,请注意在使用var但跨越多行时忘记逗号.有人昨天在我的代码中发现了这个:
var srcRecords = src.records
srcIds = [];
Run Code Online (Sandbox Code Playgroud)
它运行但效果是srcIds声明/赋值是全局的,因为由于自动分号插入,因为该语句被认为已完成,因此前一行上的var的本地声明不再适用.
我发现的 JavaScript自动分号插入的最上下文描述来自一本关于Crafting Interpreters的书。
JavaScript 的“自动分号插入”规则很奇怪。其他语言假设大多数换行符是有意义的,并且在多行语句中只有少数应该被忽略,而 JS 则假设相反。除非遇到解析错误,否则它将所有换行符视为无意义的空格。如果是,它会返回并尝试将前一个换行符转换为分号以获得语法上有效的内容。
他继续将其描述为代码气味。
如果我详细说明它是如何工作的,那么这个设计说明就会变成设计谩骂,更不用说这是一个坏主意的所有各种方式。一团糟。JavaScript 是我所知道的唯一一种语言,其中许多样式指南要求在每个语句后显式分号,即使该语言理论上允许您省略它们。
| 归档时间: |
|
| 查看次数: |
150570 次 |
| 最近记录: |