Day6【代码规范】初识 ESlint 与 检查规则

Linter介绍

从这一章我们进入到 ESLint 的学习。

linter 发展史

首先和大家来聊一聊关于 linter 的发展史。

静态代码分析

早在 1978 年,Stephen C. JohnsonDebug 自己的 C 语言项目时,突然想到为什么不做一个工具来提示自己写的代码哪里有问题呢? 这个工具也被称为 Linter

Linter 本意指的是衣服上多出来的小球、绒毛和纤维等,如果你刚把晾晒好的衣服收下来就会发现这些小玩意。以前如果想把这些多出来的"残渣"去掉,最简单的方法就是找一个单面胶粘一下再撕开,后来有的人发明了这个神器,一滚就能清除掉:

这就是 Linter 的由来,不过区别是神器重点在 "清除",而 Linter 重点在 "上报错误"。

Linter 想要提示错误,那首先就得阅读代码,这也是为什么 Linter 也被称为静态代码分析的工具。阅读完之后,再加上我们人为自定义好的一些规则,那么 Linter 就拥有了提示错误的能力了。

JSLint

2002 年,Douglas Crockfor d 就为 JavaScript 写了第一个 Linter 工具:JSLint

你现在也可以在这个网站上粘贴你的 JavaScript 代码来检查有没有问题。

JSLint 的优点就是 开箱即用,不需要配置太多的东西,相当于拎包入住。但优点也是缺点,就是 规则太严格,完全不可扩展和自定义配置,连配置文件都没有。

JSHint

JSLint 的基础上,在 2010 年的时候 Anton Kovalyov 跟其它人就 fork 了一份 JSLint 然后改造成了 JSHint

你可以在这个网站访问到 JSHint

这个工具与 JSLint 的思路正好相反,它的默认规则非常松散,自由度非常高。但是也同样带来了问题:你需要非常了解这些规则才能配出一个好用的规则表。因为规则太不严格,过于自由,所以单纯靠默认的规则跟没有配置 Linter 一样。

JSCS

前面的 JSLintJSHint 主要功能都是检查代码质量问题的,JSCS (JavaScript Coding Style) 则是一个代码风格检查器。

它有超过 90 条规则,你也能自己创建规则,不过这些规则主要是和代码风格、代码格式化有关,它不会报任何和 JS 代码质量相关的错误。

尽管 JSCS 在其活跃时期非常受欢迎,但它已于 2016 年被宣布停止维护,并建议用户迁移到 ESLintESLint 是一个更强大、更灵活的工具,它不仅可以检查代码风格,还可以发现潜在的错误和代码质量问题。另一个流行的代码格式化工具是 Prettier,它专注于自动格式化代码,而不提供任何代码质量检查。

虽然 JSCS 不再被维护,但它的一些功能和理念已经被 ESLintPrettier 等现代工具所采纳。如果你正在寻找一个代码风格检查器和格式化器,建议使用 ESLintPrettier 来替代 JSCS。这两个工具可以很好地协同工作,ESLint 负责检查代码质量,而 Prettier 负责自动格式化。

ESLint

接下来就是我们的主角 ESLint 了。

2013 年,一个叫 JSChecker 的小项目被改名成我们如今非常熟悉的 ESLint

ES6 上线了之后,JSHint 受不了直接投降了,因为它不支持这些 ES6 新语法。而 ESLint 正好异军突起,马上用 Esprima (一个高性能的 ECMAScript parser )支持所有 ES6 新语法,并对新语法做好了校验。

除了基础的 ES6 代码质量校验,ESLint 还支持代码风格的规则。开发者不仅可以自定义项目要用哪些规则,也能直接无脑使用社区上制定的规则(比如 eslint-config-airbnb)。

这一波操作也让 ESLint 成为现在 JavaScript 的一个标准的 Linter 了。然而,关于 Linter 的故事还没结束。

2012 年微软公布了第一版的 TypeScript ,随之而来的还有一个叫 TSLintLinter

在那段时间里,TSLintTypeScript 的标准 Linter 工具,ESLint 则为 JavaScript 标准 Linter 。它们各有自身特色:ESLintTSLint 所没有的一些语法特性支持,而 TSLint 可以对代码进行静态分析和类型检查。

可是,一份代码还要两个 Linter 并行检查属实有点让人不爽。TSLint 也经常和 ESLint 的人探讨应该用哪个作为主力 LinterTS 的社区也有很多声音希望优先满足 JSer 的需求,毕竟 TSJS 的超集嘛,还是以 ESLint 为主。

最终,在 2019TSLint 宣告不再维护,以后就是 ESLint 的天下了。

ESLint 核心概念

接下来我们来了解一下 ESLint 的核心概念,这个部分很重要,因为我们后期的学习就是围绕着这几个方面展开的。

ESLint 的核心概念包括以下几点:

  1. 规则 (Rules ):规则是 ESLint 的核心,它们是独立的脚本,用于检查代码中的特定问题。ESLint 有许多内置规则,这些规则可以覆盖各种编码风格和潜在错误。规则是可配置的,每个规则可以被启用或禁用,并可以设置为警告或错误级别。

  2. 配置 (Configuration ):ESLint 允许通过配置文件自定义规则的启用和设置。配置文件可以是 .eslintrc .* 格式的文件或 package.json 文件里的 eslintConfig 字段。配置可以继承其他配置,这使得可以轻松地共享和组合规则集。共享配置通常是一个 npm 包,可以被多个项目使用。

  3. 插件 (Plugins ):插件是可扩展 ESLint 功能的方式,它们包含一组自定义规则和/或处理器(见下文)。这使得 ESLint 可以适应不同的编码风格和技术栈。插件可以通过 npm 安装并在配置文件中引用。

  4. 处理器 (Processors ):处理器是一个可选的插件特性,它可以对非 JavaScript 文件进行预处理,以便 ESLint 可以检查这些文件中嵌入的 JavaScript 代码。例如,HTML 文件中的 <script > 标签或 Markdown 文件中的代码块。

  5. 命令行接口 (CLI ):ESLint 提供了一个命令行接口,用于在终端中执行 linting 操作。CLI 允许用户指定一个或多个文件、目录或 glob 模式以进行检查。CLI 还支持许多选项,这些选项可以覆盖配置文件中的设置,如禁用特定规则、规定输出格式等。

ESLint 快速上手

首先创建一个 eslint-demo 的项目,使用 pnpm init 进行格式化,安装 eslint

bash 复制代码
pnpm add eslint -D

接下来在项目根目录下面创建一个 src/index.js,代码如下:

js 复制代码
const hello = "world";
console.log(hello);

function sayHello(name) {
  console.log("Hello, " + name + "!");
}

sayHello("world");

上面随便写了一些代码,接下来在项目根目录下面创建一个 eslint 的配置文件 .eslintrc,里面会书写一些配置信息:

js 复制代码
{
  "env": {
    "browser": true,
    "es2021": true
  },
  "extends": "eslint:recommended",
  "parserOptions": {
    "ecmaVersion": 12,
    "sourceType": "module"
  },
  "rules": {
    "indent": ["error", 2],
    "quotes": ["error", "single"],
    "semi": ["error", "always"]
  }
}
  • env:主要是定义预设的全局变量

    • browser:这份配置适用于浏览器环境,预定义了诸如 window、document 之类的浏览器才会有的全局变量
    • es2021: 表示我们使用的是 ES 2021 的标准,肯定会预定义一些新版本的全局变量,Promise、Symbol 这些全局变量是支持的
  • extends:这里我们所设置的值为 eslint:recommended,这其实是 ESLint 团队推荐的一组核心规则,你可以将其视为最佳实践

  • parserOptions:和解析器相关的配置

    • ecmaVersion:使用的 ECMAScript 的版本,12 也就是 2021
    • sourceType:模块类型,这里设置为 module,表示我们使用的 ESM 模块规则,支持 import 和 export 语法
  • rules:定义代码风格,功能类似于 prettier

    • indent:缩进,我们这里设置的是两个空格,如果不符合要求,会报 error 类型的错误
    • quotes:引号的设置,这里我们设置的是单引号,如果不符合要求,会报 error 类型的错误
    • semi:每一条语句添加分号,如果不符合要求,会报 error 类型的错误

最后修改 package.json,添加如下的 script 脚本命令:

js 复制代码
"scripts": {
    // ...
    "lint": "eslint ."
},

上面的脚本命令表示对当前项目所有的 js 文件进行 lint 检查。

使用 ESlint 进行代码检查的时候,是支持自动修复的,但是并非所有的错误都能够自动修复,只能够修复一部分。

要自动进行修复,只需要添加命令行参数 --fix 即可

js 复制代码
"scripts": {
    // ...
    "lint": "eslint --fix ."
},

检查规则

规则是 ESLint 中一个比较重要的核心概念之一,因为究竟报不报错,是由规则来确定的。

规则的重要性

在 ESLint 中,本身可以配置规则的重要性,总共分为三个级别:

  • off 或者 0: 关闭这条规则
  • warn 或者 1:这条规则的级别为警告级别
  • error 或者 2:这条规则的级别为错误级别

例如:

js 复制代码
{
  "rules": {
    "no-undef": "error",
    "semi": ["warn", "always"]
  }
}

在上面的规则配置中,semi 对应的值为一个数组,数组的第一项是上面所说的规则重要性,第二项则是该条规则配置可选项,关于这个配置可选项,不同的规则能够填入的值是不一样的。关于具体能够填写的值,那么就要去这条规则的说明页面去查阅。

接下来我们就针对 semi 这条规则做一个介绍,semi 可配置值如下:

  • always:这是默认值,代表语句结束需要插入分号
  • never: 在没有 ASI 风险情况下,不需要插入分号

ASI 英语全称叫做 automatic semicolon insertion,这个翻译成中文就是自动分号插入。所谓 ASI 风险,是指由于有这个机制,可能会导致意外的行为或者错误。

js 复制代码
function example() {
   return
       {
           message: 'Hello, world!'
       }
}

在上面的代码中,我们本意是要返回一个对象,但是由于 ASI 机制,这里就会产生意外的行为,导致这个函数返回一个 undefined 而非预期的对象。

如果值为 always,那么还可以配置一个额外的对象:

  • omitLastInOneLineBlock:配置为 true,表示禁止在单行代码块中的最后一个语句使用分号
  • omitLastInOneLineClassBody:配置为 true,表示禁止在单行类里面的最后一个语句使用分号

如果值为 never,那么也是可以配置一个额外的名为 beforeStatementContinuationChars 的对象:

  • "beforeStatementContinuationChars ": "any"(默认):如果下一行以[, (, /, +, 或 -]开始,则忽略语句末尾的分号(或缺少分号)
js 复制代码
let a = 1
+1 // 正确:分号被忽略

let b = 2
;+2 // 正确:分号也可以
  • "beforeStatementContinuationChars ": "always":如果下一行以[, (, /, +, 或 -]开始,则要求在语句末尾使用分号
js 复制代码
let a = 1
+1 // 错误:要求在语句末尾使用分号

let b = 2
;+2 // 正确:添加了分号
  • "beforeStatementContinuationChars ": "never ":即使下一行以[, (, /, +, 或 -]开始,只要没有引起 ASIAutomatic Semicolon Insertion,自动分号插入)的风险,也禁止在语句末尾使用分号
js 复制代码
let a = 1
+1 // 正确:没有 ASI 风险,不需要分号

let b = 2
;+2 // 错误:不允许在没有 ASI 风险的情况下使用分号

规则注释

在具体的代码文件里面,可以以注释的方式来配置规则

js 复制代码
/* eslint eqeqeq: "off", curly: "error" */
/* eslint eqeqeq: 0, curly: 2 */
/* eslint quotes: ["error", "double"], curly: 2 */

规则注释的优先级会高于配置文件里面的规则。

一般在如下的场景中可能会涉及到使用注释规则:

  1. 针对特定的文件或者代码片段需要指定特殊规则,比如我们针对某一个代码片段去禁用 ESLint 检查
js 复制代码
/* eslint-disable */
console.log('Hello')
/* eslint-enable */

或者只禁用某一个规则

js 复制代码
/* eslint-disable semi */
console.log("Hello");
/* eslint-enable semi */
  1. 指定某个文件的特殊配置,有时我们需要针对某个文件指定和其他文件不同的 ESLint 配置,这种情况下也可以使用注释的形式,这样就不需要去修改主要的配置文件
js 复制代码
/* eslint-env node, mocha */

在上面的注释汇总,我们声明 ESLint 的检查环境为 node 和 mocha,这就意味着在检查该文件的时候,ESLint 会预设一些 node 和 mocha 中的全局变量,比如 process、describe、it。

  1. 临时禁用某条规则
js 复制代码
// eslint-disable-next-line no-unused-vars
const tempVariable = 'Temporarily not used';

在上面的注释中,我们使用了 eslint-disable-next-line,代表只禁用下一行的代码检查,后面跟上了具体的规则,表示禁用下一行代码的某一条规则的检查,不影响之后的代码。

另外在配置文件中,有如下的配置选项:

  • noInlineConfig:禁止行内注释形式的规则
  • reportUnusedDisableDirectives:用于是否报告有未使用的 eslint-disable 指令

例如:

js 复制代码
/* eslint-disable-next-line no-console */
console.log('Hello');

上面的代码是可以正常工作的,eslint-disable-next-line no-console 这条行内注释规则是有用的,但是如果我们把下面的 console 注释调用:

js 复制代码
/* eslint-disable-next-line no-console */
// console.log('Hello');

那么上面的这一条行内注释规则就变成了一条无用的注释规则

更多关于行内注释规则,可以参阅官网资料:eslint.org/docs/latest...

规则参照表

你可以在 eslint.org/docs/latest... 看到 ESLint 里面的所有规则

在官方的规则参照表中,每一条规则后面有三个符号,对应的含义如下:

🔧 💡
在配置文件中的 "extends ": "eslint :recommended" 属性会启用此规则。 此规则报告的一些问题可以通过 --fix 参数自动修复。 此规则报告的一些问题可以通过编辑器建议手动修复。
相关推荐
可缺不可滥10 分钟前
前端 性能优化 (图片与样式篇)
前端·性能优化
Bug从此不上门11 分钟前
Nuxt3之使用lighthouse性能测试及性能优化实操
前端·javascript·性能优化·vue·fetch·nuxt3
Apache IoTDB31 分钟前
IoTDB 与 HBase 对比详解:架构、功能与性能
大数据·数据库·架构·hbase·iotdb
拼图20940 分钟前
Vue.js开发基础——数据绑定/响应式数据绑定
前端·javascript·vue.js
刘志辉44 分钟前
vue反向代理配置及宝塔配置
前端·javascript·vue.js
星叔1 小时前
ARXML汽车可扩展标记性语言规范讲解
java·前端·汽车
编程老船长1 小时前
第18章 从零开始:春节门联网页设计,用DIV+CSS打造传统与现代的完美融合
前端·css·html
sky.fly1 小时前
HTML5+css3(浮动,浮动的相关属性,float,解决浮动的塌陷问题,clear,overflow,给父亲盒子加高度,伪元素)
前端·css·html
Coisini_甜柚か2 小时前
打字机效果显示
前端·vue3·antv
郑小憨2 小时前
Node.js NPM以及REPL(交互式解释器) 使用介绍(基础介绍 二)
开发语言·前端·javascript·npm·node.js