> 技术文档 > 一个没有手动加分号引发的bug

一个没有手动加分号引发的bug

最近因为分号的疏忽,导致出现了一个bug,记录下来,分享给大家。

1、一个示例

给你下面这一段代码,你根据经验判断一下运营结果

let [a,b] = [\'a\',\'b\']let [x,y] = [1,2]if(x < y){ [x,y] = [y,x] [a,b] = [b,a]}

按照一般的理解,是不是应该是 x = 2,y=1,a = ‘b’,b = ‘a’ ?
可实际呢?咱们跑一下看看:

console.log([x,y]) // [\'b\', \'a\']console.log([a,b]) // [\'a\',\'b\']

2、为什么呢?

这段代码不加分号会导致 [x,y][a,b] 被错误解析为一个连续表达式,从而引发赋值错误。根本原因是 JavaScript 的 自动分号插入(ASI) 机制在以下情况 不会插入分号

  1. 当下一行以 [ 开头时,会被解析为当前语句的延续
  2. 赋值表达式可以跨行解析

3、错误解析过程(无分号时):

if(x < y){ [x,y] = [y,x] // 注意这里没有分号 [a,b] = [b,a] // 被解析为上一行的延续}

JavaScript 引擎会将其解析为:

[x,y] = [y,x][a,b] = [b,a]

这实际等价于:

// 1. 先计算 [y,x][a,b]// - [y,x] 是一个数组 [2, 1] // - [a,b] 是逗号表达式,返回最后一个值 \'b\'const temp = [y,x][\'b\'] // 相当于访问数组的 \'b\' 属性// 2. 将 [b,a] 赋值给上述结果temp = [b,a]// 再将 temp 赋值给 [x,y] [x,y] = temp// 也就是[x,y] = [b,a]

最终导致 xy 被赋值为 [b,a](即 [\'b\',\'a\']

4、加分号后验证代码:

let [a,b] = [\'a\',\'b\']; // a=\'a\', b=\'b\'let [x,y] = [1,2]; // x=1, y=2if(x < y){ [x,y] = [y,x]; // 正常交换:x=2, y=1 [a,b] = [b,a]; // 正常交换:a=\'b\', b=\'a\'}console.log(x, y); // 输出: 2 1console.log(a, b); // 输出: b a

5、解决方案:

5.1. 始终添加分号(推荐)
// 正确写法[x,y] = [y,x]; // 明确分号结束[a,b] = [b,a];
5.2. 使用防御性分号
// 在可能引起歧义的语句前加分号;[a,b] = [b,a]
5.3. 用逗号写成单行
// 单行写法避免换行问题if(x < y){ [x,y] = [y,x], [a,b] = [b,a] }

6、关键教训:

  1. 避免以 [( 开头的行
    这类语法结构容易与前一行的表达式粘连

  2. 解构赋值后必须加分号
    特别是在块语句(if/for 等)内部

  3. 使用 ESLint 规则
    配置 semi: [\"error\", \"always\"] 强制分号使用:

    // .eslintrc.json{ \"rules\": { \"semi\": [\"error\", \"always\"] }}