问题背景
前一段日子团队通过ESLint + Prettier +StyleLint
刚刚统一了代码规范。我本地通过编辑器设置了保存时执行eslint fix,偶然的发现了一个报错…
根据提示,在每一个[
前加一个;
,果然没问题了。但是我们团队的代码规则是不需要分号的,我觉得这样很不美观。想知道报错的根本原因,(其实当时怀疑这是prettier的一个BUG),于是就继续探究了下去。
分号的作用
分号也是一个执行语句,叫做空语句,分号是断句用的,每一个分号就是一个程序语句结束的标志。
知乎上有一段比较可爱的代码。
for(var i=1; i<=5; i++) {
console.log(i)
}
for(var i=1; i<=5; i++);{
console.log(i)
}
应该很容易看的看出
第一段输出的是1,2,3,4,5
第二段输出的是6
第二段for循环后面加了;后,for循环后面的代码块就和for循环没有关系了。而for循环的代码,全部都执行在了空语句;上面。
接下来再看下一段代码
var a = 4
var b = [1,2,3]
[a]
console.log(b)
这时候输出b的是undefined
,并不是我以为的[1,2,3]
。
原来在代码解析的时候,变成了
var a = 4
var b = [1,2,3][a]
console.log(b)
并没有通过换行符截断代码。
看来随处添加或者删除分号还是有风险的。但是为什么有的地方可以不加,有的地方不加分号却会报错呢?在查询这个问题的时候,发现了一个名词:Automatic Semicolon Insertion (ASI 自动插入分号机制)。下面会描述这个概念。
分号的添加规则
除了以下的语句,JavaScript的每一个语句都应该加分号的。
- 循环语句: for, while
- 分支语句: if, switch, try
- 函数声明 (不是函数表达式)
原来除了这几个特殊的语句之外,所有的语句都应该加分号的,那我们团队的规则不就错了吗😱😱😱?憋捉急,接下来就是ASI
登场了。
ASI
自动插入分号机制…噢,顾名思义,那么应该是在代码解析的时候,解析器会自动插入我们忘记的分号呀!
并不是!!!(啪啪啪的打脸声响起👏👏👏)
抽象语法树中并没有分号这个东西。插入分号只是一个概念,意思是解析器除了分号,还会把换行符当作断句的依据,从而保证语句解析的正确性,并不是真的往里插一个分号(当然了,你本地压缩代码的时候,emmm,应该是需要真的插入的)。
但是ASI并不是将所有的换行符都识别成分号,而是通过以下规则。
ASI的插入规则
大前提,ASI的纲领:
以换行为基础。(就是你肯定得有换行符才行)
JS解析器是尽量把语句合并成同一行的解析的。只有符合ASI规则的时候,才会加入分号进行断句。
1、新行并入当前行将构成非法语句,自动插入分号。
if(true)
a = 1
console.log(a)
// 解析为
if(true) a = 1;
console.log(a);
这个代码就清楚了解释了纲领。
必须存在换行符。你写成一行if(true) a = 1 console.log(a)
直接就报错了。
尽量并为一行。并没有解析成如下代码。
if(true);
a = 1;
console.log(a);
因为第二行并入第一行没有构成非法语句。
2、在continue, return, break, throw后自动插入分号。
这些语句后面的换行符会自动插入分号的。
return
123
// 解析为
return;
123;
这种写法就return了个寂寞。这就是为什么在返回大量代码的时候喜欢让你在 return后面加一个()
包裹着你的返回内容。
3、++、–后缀表达式作为新行的开始,在行首自动插入分号
var a = 1
var b = 2
a
++
b
// 解析成了
var a = 1
var b = 2
a;
++b;
如果你本身就想写++b
那还好点,但是如果你的本意是a++
呢。结果却是b自增了。这也是为什么很多的代码规则里不建议你用++,--
,而是用 +=1,-=1
。
4、当出现一个不允许的行终止符或}
时,会在其之前插入一个分号。
function(){ a = 1 }
// 解析成了
function(){ a = 1; }
接下来我们就得知道什么情况下不会触发ASI了
就一句
新的一行以(, [, /, +, -, *, %, ,, .开头
因为这些符号开头的话,根据上述的ASI的第一条规则,这一行和上一行并成一行的时候,并不会形成非法语句。例如[]会被识别成属性。()
会被识别成函数执行语句。
解决方法就是在新一行的开始,手动加一个分号即可。
ASI会不会影响代码的效率呀
解析的时候应该会有一点点点点点点的影响吧,执行的时候都一样,没啥影响。但是现在项目都是本地打包压缩好的。所以大部分情况下不用考虑这些问题,跟着团队规范走就行了。
那么到底应该加不加分号呢?
上面说的这么多其实和代码规范没有关系,讲的是ASI机制。加不加分号一看个人习惯喜好,二看团队要求。规范上加不加并没有对错之分,但是你都要对ASI了解。
来源:掘金