JS分号补全机制
这里我们来讨论一个经典问题:
JS到底要不要写分号
首先我们要知道的是,JS并不是不需要分号的,行尾写分号事实上是一种为编译器减少负担的行为。JS对此的操作是根据一定规则主动插入分号。
我的观点是,既然JS已经提供了如此方便的规则,那我们为什么不用呢是吧?那么这里,我们的问题就转变为了:
JS不加分号什么时候会出错
要解答这个问题,还要从自动插入分号的规则说起。
自动插入分号规则
有换行符,且下一个符号是不符合语法的,那么就尝试插入分号。
有换行符,且语法中规定此处不能有换行符,那么就自动插入分号。
当代码符合以上规则的时候,JS会自动在行尾插入分号。下面举一些例子:
规则1
let a = 0
if(true){}
在这个例子中,在a=0之后出现了换行符,并且a=0if()这样的写法显然是不符合语法的,因此JS将在第一行行尾插入分号。
规则2
a
++
b
这是一种很奇怪的写法,但是刚好符合了这里的第二条规则,在JS的标准定义中,有如下要求
UpdateExpression[Yield, Await]:
LeftHandSideExpression[?Yield, ?Await]
LeftHandSideExpression[?Yield, ?Await][no LineTerminator here]++
LeftHandSideExpression[?Yield, ?Await][no LineTerminator here]--
++UnaryExpression[?Yield, ?Await]
--UnaryExpression[?Yield, ?Await]
注意这个定义中的[no LineTerminator here]
,这个标签表示在左侧的表达式与右侧的++符号之间不能存在换行符。可以看到,在标准定义中,++放置于左侧时,并没有要求不能换行,而在右侧进行++时,则出现了这个要求。
根据这个规则,我们再回头看看上面的代码,在前两行之间,存在换行符,而根据标准定义,a与++之间是不能存在换行符的,因此,JS将在第一行结尾处插入分号。而后两行之间,由于++与b之间虽然存在换行符,但是定义中并未要求他们之间不能出现换行符,因此第二行并未添加分号。上面的代码结果上等同于:
a;
++b;
这条规则实际上no LineTerminator here 规则强相关,那么我们就找出JavaScript语法定义中的这些规则。
没有手动添加分号会出现混淆的情况
以括号开头的语句
//这是一种IIFE的写法,在实际使用时需要注意加上分号 (function(a){ console.log(a); })()/*这里没有被自动插入分号*/ (function(a){ console.log(a); })()
以正则表达式开头的语句
var x = 1, g = {test:()=>0}, b = 1/*这里没有被自动插入分号*/ /(a)/g.test("abc") console.log(RegExp.$1)
以数组开头的语句
var a = [[]]/*这里没有被自动插入分号*/ [3, 2, 1, 0].forEach(e => console.log(e))
以模板字符串开头的语句
var f = function(){ return ""; } var g = f/*这里没有被自动插入分号*/ `Template`.match(/(a)/); console.log(RegExp.$1)
JS分号补全机制
http://localhost:8080/archives/jsfen-hao-bu-quan-ji-zhi