自动分号补齐(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的规则,分号只加在必要的地方即可。