随着近两年前端工具领域的一些重大变化,我不仅重新考虑了前端的构建方式,还重新考虑了代码的编写方式。
我已经从Webpack和Parcel换到了Vite,从 JavaScript 换到了 TypeScript,基于类/对象的组件换到了基于 Hook/Composition 的组件。现在随着边缘计算的到来,也许我会花更多的时间使用 Next、Remix 和 Nuxt 等元框架。
最近,我一直在思考的一个多年来没有想过的东西:分号。
其实,您对 JavaScript 的任何看法,都可能是对的。此时,有一个问题又被提出:我们真的需要 JavaScript 中的分号吗?
从技术的角度来说,在现代的前端领域,这个问题的答案是否定的。
现在,几乎所有新的前端项目都以由 CLI 或者 npm 初始化程序开始的,它们都可以选择(或者默认包含)linting、格式化、转译和编译的工具。
我们设置这些基础标准,为了让开发的体验更好,并在团队之间保持代码一致。有了这些工具的帮助,我认为可以不要 JavaScript 中的分号。当然,这个问题没有正确答案,完全是个人喜好问题。
需要明确说明的是,分号本身并不尴尬,尴尬的插入分号这件事儿。在技术上,分号有无是“可选的”,但是它确实会导致一些异常情况。
关于分号,ESLint 文档解释得很好,说明如下:
JavaScript 不需要在每条语句的末尾使用分号。在许多情况下,JavaScript 引擎可以确定分号应该在某个位置并自动添加它。该功能称为 自动分号插入 (ASI) ,这被认为是 JavaScript 中更具争议的功能之一。
例如,下面的代码是正确的:
var name = "ESLint" var website = "eslint.org"; 复制代码
在第一行,JavaScript 引擎会自动插入一个分号,所以这不被认为是语法错误。JavaScript 的引擎知道如何解释该行代码,并且知道行尾表示语句结束了。
分号可能会导致两种异常问题的发生:
示例代码如下:
return { name: "ESLint" }; 复制代码
JavaScript 引擎会将这段代码解释为:
return; { name: "ESLint"; } 复制代码
这样就会造成 return
后直接返回,导致它下面的代码无法访问。
示例代码如下:
var globalCounter = { } (function () { var n = 0 globalCounter.increment = function () { return ++n } })() 复制代码
JavaScript 引擎会将这段代码解释为:
var globalCounter = { } (function () { var n = 0 globalCounter.increment = function () { return ++n } })(); 复制代码
JavaScript 引擎不会在第一行之后插入分号,从而导致运行时错误(误将空对象作为函数调用)。
现在,我们已经了解了分号在 JavaScript 中是如何工作的。接下来介绍一下使用哪些工具可以避免上面遇到的异常情况。
常见的有三个工具:
这三个工具可以很好地协同工作,每个都可以针对前面描述的异常情况提供对应的保护机制。
ESLint是最流行的 JavaScript linter。它的配置非常灵活,并带有开箱即用的推荐规则。
要配置 ESLint 在不使用分号的情况下也可以正常工作,只需要指定三个规则:semi、no-unreachable和no-unexpected-multiline。
可以将下面的代码片段添加到块.eslintrc.{js,yml,json}
下的配置文件rule
中:
rules: { semi: ['error', 'never'], 'no-unreachable': ['error'], 'no-unexpected-multiline': ['error'] } 复制代码
Prettier是一个专一的代码格式化工具,唯一的目的就是格式化你的代码。
一般情况下,Prettier 会与 ESLint 一起配合使用,效果更佳。
我们可以将 Prettier 配置为自动从代码中删除分号,需要在.prettierrc.json
配置文件中增加如下设置:
{ "semi": false } 复制代码
TypeScript 编译器是这三个工具中最简单的,因为它不需要配置就可以使用没有分号的语言。只要您使用 TypeScript 语言开发。
虽然它没有涵盖所有边缘情况,但当其中一些 ASI 故障导致对 TypeScript 类型系统的无效使用时,编译器会发出错误。
尽管,上述工具可以帮助我们处理没有分号的异常情况,但是仍然有一些情况可以使用分号: