摘要: JavaScript 语言从设计之初就是考虑带分号的, 使用不带分号的编码规则就要小心点啦.
背景
最近在项目中开始使用新的编码规范, 一开始 ESLint 报一大堆错误, 改得我想砸键盘, 花了好些时间才适应, 下面列出一些代表性的规则:
只能使用单引号
函数定义的圆括号和左大括号之间一定要有空格:
function(args) { .. }
import 语句在大括号之后一定要有空格:
import { fa, fb } from moduleC
不用分号!!!
起因
早上在实现一个功能的时候, 写了一个 map 函数来复用部分代码. 程序运行起来后, 没有执行结果, 而且没有报错. 通过 console.log 打印数据发现, 整个程序执行到 map 前面就再也不往下走了, 很奇怪. 因为没有报错信息, 无法推测具体原因. 于是, 我将其抽象成非常简单的代码来排查. 如下所示:
- console.log("hello, fundebug")
- [1, 2, 3].map(i=>console.log(i))
然后执行看看结果如何:
在项目中没有报错, 单独将这段代码拿出来在浏览器控制台下执行却报错了!
这么简单的代码为什么会出错呢? 第一反应就是 JS 引擎将代码生成语法树的时候, 可能解析不正确. 于是, 我在第一行末尾加分号测试.
- console.log("hello, fundebug");
- [1, 2, 3].map(i=>console.log(i))
程序正确执行了:
这让我更加犯难, 如果不加分号会导致程序出错, 那么为什么还会推崇这样的编码规范呢?
在网络上搜索 JavaScript 关于分号的 BUG, 发现有非常多关于要不要使用分号的讨论.
大宗师 Douglas Crockford 表示要正确使用分号
引用 minhan 在扯不完的 JS 分号问题文中的论述:
JSON,JSLint,JSMin 和 ADSafe 的创造者, ECMA JavaScript 2.0 标准化委员会委员, 被 JavaScript 之父 Brendan Eich 称为 JavaScript 的大宗师, 名著《JavaScript: The Good Parts》(中文版《JavaScript 语言精粹》) 的作者 Douglas Crockford 直接怼之: 这代码真尼玛的疯狂傻 X, 我是不会为了这傻 X 的案例而去降低 JSMin 的级数; TC39 正在考虑将『!』号作为中缀运算符使用, 这个代码不久将来就运行不了. 赶紧修复吧, 学学怎么正确地使用分号.『!』号并不语句的分隔号,『;』才是.
JSMin 处理如下代码后无法正确执行:
- clearMenus()
- !isActive && $parent.toggleClass('open')
自动分号插入机制
JavaScript 有着自动分号插入的机制 (Automatic Semicolon Insertion), 简称 ASI. 这是一个辅助性的功能, 然后有一些情况要注意:
如果你这样写代码:
return a + b
那么自动分号插入后会这样:
return; a + b;
更可能导致隐含 BUG 的状况是:
- a = b + c
- (d + e).print()
他不会自动插入分号, 因为第二行一括号开始, 会被误认为是函数.
a = b + c(d + e).print();
所以, 我刚刚的的代码在自动插入分号后, 应该是这样:
console.log("hello fundebug")[1,2,3].map(i=>console.log(i))
那么这样看来, 用分号才是最安全的做法咯!
如果你不想用分号, 又怕出问题, v2ex 上有位童鞋给出了一个速记方案 https://www.v2ex.com/t/315055 :
如果你写 JS 代码不喜欢带分号, 而又搞不清什么时候必须加分号, 可以这么做: 在以 "(","[" ,"/","+","-" 开头的语句前面都加上一个分号.
我最终的解法是先声明一个变量来指向这个数组, 这样就可以避免以 [开头, 又不使用分号:
- let indexArray = [1, 2, 3]
- indexArray.map(i=>console.log(i))
关于 Fundebug
来源: https://juejin.im/entry/5ba0430be51d450e84779dd7