版本

semi

要求或禁止使用分号代替 ASI

🔧 可修复

此规则报告的一些问题可以通过 --fix 命令行 选项自动修复

重要

此规则在 ESLint v8.53.0 中已弃用。请使用 @stylistic/eslint-plugin-js 中的相应规则

了解更多

JavaScript 不要求在每个语句末尾使用分号。在许多情况下,JavaScript 引擎可以确定在某个位置应该有一个分号,并会自动添加它。此功能称为 自动分号插入 (ASI),被认为是 JavaScript 中较具争议的功能之一。例如,以下两行都是有效的

var name = "ESLint"
var website = "eslint.org";

在第一行,JavaScript 引擎将自动插入分号,因此这不被认为是语法错误。JavaScript 引擎仍然知道如何解释该行,并且知道行尾表示语句的结尾。

在关于 ASI 的争论中,通常有两种思想流派。第一种是我们应该像 ASI 不存在一样对待它,并始终手动包含分号。理由是始终包含分号比试图记住何时需要或不需要分号更容易,从而降低了引入错误的可能性。

然而,对于使用分号的人来说,ASI 机制有时可能很棘手。例如,考虑以下代码

return
{
    name: "ESLint"
};

这可能看起来像一个 return 语句,它返回一个对象字面量,然而,JavaScript 引擎会将此代码解释为

return;
{
    name: "ESLint";
}

实际上,在 return 语句之后插入了一个分号,导致它下面的代码(块内的标记字面量)变得不可访问。此规则和 no-unreachable 规则将保护您的代码免受此类情况的影响。

另一方面,争论的另一方是那些认为既然分号是自动插入的,那么它们是可选的,不需要手动插入。然而,对于不使用分号的人来说,ASI 机制也可能很棘手。例如,考虑以下代码

var globalCounter = { }

(function () {
    var n = 0
    globalCounter.increment = function () {
        return ++n
    }
})()

在这个例子中,在第一行之后不会插入分号,从而导致运行时错误(因为一个空对象被当作函数调用)。no-unexpected-multiline 规则可以保护您的代码免受此类情况的影响。

虽然 ASI 允许您在编码风格上有更大的自由度,但无论您是否使用分号,它也可能使您的代码以意想不到的方式运行。因此,最好了解 ASI 何时发生以及何时不发生,并让 ESLint 保护您的代码免受这些潜在的意外情况的影响。简而言之,正如 Isaac Schlueter 曾经描述的那样,\n 字符总是结束一个语句(就像分号一样),除非以下情况之一为真

  1. 语句有一个未闭合的括号、数组字面量或对象字面量,或者以其他无效的方式结束语句。(例如,以 ., 结尾。)
  2. 该行是 --++(在这种情况下,它将递减/递增下一个 token。)
  3. 它是一个 for()while()doif()else,并且没有 {
  4. 下一行以 [(+*/-,. 或其他只能在单个表达式中的两个 token 之间找到的二元运算符开头。

规则详情

此规则强制执行分号的统一使用。

选项

此规则有两个选项,一个字符串选项和一个对象选项。

字符串选项

  • "always"(默认)要求在语句末尾使用分号
  • "never" 禁止在语句末尾使用分号(除了消除以 [(/+- 开头的语句的歧义)

对象选项(当 "always" 时)

  • "omitLastInOneLineBlock": true 禁止在花括号(以及块的内容)在同一行中的块中使用最后一个分号
  • "omitLastInOneLineClassBody": true 禁止在花括号(以及类主体的内容)在同一行中的类主体中使用最后一个分号

对象选项(当 "never" 时)

  • "beforeStatementContinuationChars": "any"(默认)忽略语句末尾的分号(或缺少分号),如果下一行以 [(/+- 开头。
  • "beforeStatementContinuationChars": "always" 要求在语句末尾使用分号,如果下一行以 [(/+- 开头。
  • "beforeStatementContinuationChars": "never" 禁止在语句末尾使用分号,即使下一行以 [(/+- 开头,也不会造成 ASI 风险。

注意: beforeStatementContinuationChars 不适用于类字段,因为类字段不是语句。

always

使用默认 "always" 选项时,此规则的 错误 代码示例

在在线演练场中打开
/*eslint semi: ["error", "always"]*/

var name = "ESLint"

object.method = function() {
    // ...
}

class Foo {
    bar = 1
}

使用默认 "always" 选项时,此规则的 正确 代码示例

在在线演练场中打开
/*eslint semi: "error"*/

var name = "ESLint";

object.method = function() {
    // ...
};

class Foo {
    bar = 1;
}

omitLastInOneLineBlock

使用 "always", { "omitLastInOneLineBlock": true } 选项时,此规则的额外 正确 代码示例

在在线演练场中打开
/*eslint semi: ["error", "always", { "omitLastInOneLineBlock": true}] */

if (foo) { bar() }

if (foo) { bar(); baz() }

function f() { bar(); baz() }

class C {
    foo() { bar(); baz() }

    static { bar(); baz() }
}

omitLastInOneLineClassBody

使用 "always", { "omitLastInOneLineClassBody": true } 选项时,此规则的额外 正确 代码示例

在在线演练场中打开
/*eslint semi: ["error", "always", { "omitLastInOneLineClassBody": true}] */

export class SomeClass{
    logType(){
        console.log(this.type);
        console.log(this.anotherType);
    }
}

export class Variant1 extends SomeClass{type=1}
export class Variant2 extends SomeClass{type=2; anotherType=3}

never

使用 "never" 选项时,此规则的 错误 代码示例

在在线演练场中打开
/*eslint semi: ["error", "never"]*/

var name = "ESLint";

object.method = function() {
    // ...
};

class Foo {
    bar = 1;
}

使用 "never" 选项时,此规则的 正确 代码示例

在在线演练场中打开
/*eslint semi: ["error", "never"]*/

var name = "ESLint"

object.method = function() {
    // ...
}

var name = "ESLint"

;(function() {
    // ...
})()

import a from "a"
(function() {
    // ...
})()

import b from "b"
;(function() {
    // ...
})()

class Foo {
    bar = 1
}

beforeStatementContinuationChars

使用 "never", { "beforeStatementContinuationChars": "always" } 选项时,此规则的额外 错误 代码示例

在在线演练场中打开
/*eslint semi: ["error", "never", { "beforeStatementContinuationChars": "always"}] */
import a from "a"

(function() {
    // ...
})()

使用 "never", { "beforeStatementContinuationChars": "never" } 选项时,此规则的额外 错误 代码示例

在在线演练场中打开
/*eslint semi: ["error", "never", { "beforeStatementContinuationChars": "never"}] */
import a from "a"

;(function() {
    // ...
})()

何时不使用

如果您不想以任何特定方式强制执行分号的使用(或省略),则可以关闭此规则。

版本

此规则在 ESLint v0.0.6 中引入。

拓展阅读

资源

更改语言