JavaScript自动分号补齐的坑

自动分号补齐(auto semicolon insertion,简称ASI)

在JavaScript中,行尾的分号有一种自动插入机制,如果新起了一行,并且这新的一行不能追加到当前语句时,会自动追加一个分号。但如果不加区分在每个表达式(Expression)和语句(statement)之后都手动输入分号,那么其中绝大部分的分号是无用的。

导致上下文解析出错时需要分号

会造成此类问题的token有6个:括号,方括号,正则开头的斜杠,加号,减号,字符串模板的反引号。当以这6个字符作为一行开头时,不会在上一行自动补全分号,造成解析出错。

a = b
(c + d).toString()

会被解析成

a = b(c + d).toString()

即()会被看做是在调用函数b,和本意不符。所以应尽量避免以这6个字符作为一行的开头,如果避免不了,可以选择在行首加分号。

绝对禁止的行结束符(restricted productions)

如果在不该换行的地方换行了,就会自动插入一个分号。

后缀表达式
   左值表达式 [无行终结符] ++
   左值表达式 [无行终结符] --
Continue 语句
   continue [无行终结符] 标识符? ;
Break 语句
   break [无行终结符] 标识符? ;
Return 语句
   return [无行终结符] 表达式? ;
Throw 语句
   throw [无行终结符] 表达式? ;

[无行终结符] 代表此处禁止换行。对于后缀表达式,遵循的原则是避免修改上一行的值。 对于 continue, break, return 和 throw,遵循的原则是:如果他们不带参数,他们不会指向下一行(会被插入一个分号)。

a
++
b

会被解析成

a;
++b

关于return 和 throw

function test() {
 return
 3
}
test()

输出的结果实际是 undefined,因为上述代码被解析成

function test() {
 return;
 3
}
test()

关于break 和 continue

var num = 0
outermost: 
for(let i = 0, j; i < 100; i++) {
 for(j = 0; j < 100; j++) {
   if(i === 50 && j===50 ) {
     break
     outermost
   }
   num++
 }
}
console.log(num)

此时break 和label标示符之间有一个换行符,此时会在break后自动补分号,outermost未起作用,输出的结果为95。当break 和 label标示符放在同一行即 break outermost时,输出结果为55。

因此笔者建议要有良好的编码习惯,弄清ASI的规则,分号只加在必要的地方即可。

参考文章

尤雨溪在知乎的回答
JavaScript 中的自动分号插入(ASI) : 迷渡

你可能感兴趣的:(JavaScript自动分号补齐的坑)