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语法定义中的这些规则。

没有手动添加分号会出现混淆的情况

  1. 以括号开头的语句

    //这是一种IIFE的写法,在实际使用时需要注意加上分号
    (function(a){
        console.log(a);
    })()/*这里没有被自动插入分号*/
    (function(a){
        console.log(a);
    })()
    
  2. 以正则表达式开头的语句

    var x = 1, g = {test:()=>0}, b = 1/*这里没有被自动插入分号*/
    /(a)/g.test("abc")
    console.log(RegExp.$1)
    
  3. 以数组开头的语句

    var a = [[]]/*这里没有被自动插入分号*/
    [3, 2, 1, 0].forEach(e => console.log(e))
    
  4. 以模板字符串开头的语句

    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
作者
Sumireeee
发布于
2025年05月29日
许可协议