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 国际许可协议进行许可