Javascript 分号自动插入机制
最近彻底从分号党变节为无分号群众,分号党的日子对 Javascript 分号的原理不求甚解,这几天仔细了解了下,这篇文章总结下 ASI(automatic semicolon insertion, 分号自动插入机制)
不能省略的分号
我在初学 Javascript 时,也搜过一些代码是否要加分号的资料,很多文章提到 「Javascript 权威指南」中的一段话
如果一条语句以
(
、[
、/
、+
、或-
开始,那么它极有可能和前一条语句合在一起解释。
并奉若圭臬,仅是这几个字符的相关例子就占据了文章的大半篇幅。
看完这些文章,我对于 Javascript 分号的认知时,除了这几个字符前面需要特殊加分号外,其余的分号均可以省略,而日常开发中,以这几个字符开始的语句很少遇到,最常见的只有以 (
开始的立即执行函数(IIFE),随着时间的推移,我只记得在立即执行函数前需要特殊加分号。
这种不求甚解的思维让我在技术学习的道路上始终踟蹰不前,其实稍微考虑深一点,就应该意识到,/
、+
、-
都在,那 *
呢?花点时间理解 IIFE 的原理就应该知道,只需要把函数声明转换成表达式直接执行就可以,除了 ()
还可以用 !
、+
、-
……
关于 ASI
虽然被称为分号自动插入,但在代码实际的解析中,并没有分号插入,这个机制用于判断输入流(input stream
)的终止。下文中,我们以插入分号代称这种终止。
ASI 机制
ECMAScript 标准定义了三条规则和两种例外情况:
规则
1.Javascript 代码在从左往右被解析的过程中,当碰到一个不能构成合法语句的 token 时,下面几个条件至少一条成立,解析器就在在这个 token 前插入分号:
- 如果这个 token 与上一个 token 之间至少有一个换行
- 如果这个 token 是
}
- 如果上一个 token 是
)
,那么解析器会尝试将前面的 token 解析为do...while
语句,并插入分号
2.如果已经读到输入流的结尾了,解析器仍旧判定语法不合法,那么会在输入流的结尾插入分号
3.如果解析过程中遇到restricted production
,当在restricted production
语法中禁止换行的位置([no LineTerminator here]
)出现换行时,解析器会在换行的位置插入分号
例外
以下情况,将不会被插入分号:
- 插入的分号被解析为空语句
for
循环中
restricted production
Update
表达式:
LeftHandSideExpression [no LineTerminator here]
++
LeftHandSideExpression [no LineTerminator here]
--
Continue
语句:
continue;
continue
[no LineTerminator here]
LabelIdentifier;
Break
语句:
break;
break
[no LineTerminator here]
LabelIdentifier;
Return
语句:
return;
return
[no LineTerminator here]
LabelIdentifier;
Throw
语句:
throw;
throw
[no LineTerminator here]
LabelIdentifier;
箭头函数:
- Parameter
[no LineTerminator here]
=>
函数体
;
Yield
表达式:
Yield
[no LineTerminator here]
*
AssignmentExpression
;Yield
[no LineTerminator here]
AssignmentExpression
;
例子
1 | { 1 |
1 | return |
1 | if(a > b) |
1 | for(a; b |
开发应用
现在我已经完全适应了没有分号的开发,之前存在的不确定因素,只需花点时间制定一个可以长期沿用的规范就能解决,例如好的开发习惯可以让我们避免使用 [].forEach()
之类的写法,同时立即执行函数也有多种写法让我们避免 (function(){})()
这种情况的出现。
参考:
作者: leeon
来源: https://leeon.im
链接: https://leeon.im/javascript-asi/
本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可