跳至内容

@stylistic/

semi

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

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

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

在关于 ASI 的争论中,一般有两种观点。第一种观点是,我们应该把 ASI 当作不存在,并始终手动添加分号。其理由是,始终添加分号比试图记住何时需要或不需要添加分号更容易,从而减少了引入错误的可能性。

但是,ASI 机制有时会让使用分号的人感到困惑。例如,考虑以下代码

js
return
{
    name: "ESLint"
};

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

js
return;
{
    name: "ESLint";
}

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

另一方面,有些人认为,由于分号是自动插入的,因此它们是可选的,不需要手动插入。但是,ASI 机制对于不使用分号的人来说也可能很棘手。例如,考虑以下代码

js
var globalCounter = { }

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

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

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

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

规则详细信息

此规则强制一致使用分号。

选项

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

字符串选项

  • "always"(默认)要求语句末尾有分号
  • "never" 不允许语句末尾有分号(除非用于区分以 [(/+- 开头的语句)

对象选项(当 "always" 时)

  • "omitLastInOneLineBlock": true 不允许在花括号(以及块的内容)位于同一行的块中使用最后一个分号
  • "omitLastInOneLineClassBody": true 不允许在花括号(以及类体的内容)位于同一行的类体中使用最后一个分号

对象选项(当 "never" 时)

  • "beforeStatementContinuationChars": "any"(默认)忽略语句末尾的分号(或缺少分号),如果下一行以 [(/+- 开头。
  • "beforeStatementContinuationChars": "always" 要求语句末尾有分号,如果下一行以 [(/+- 开头。
  • "beforeStatementContinuationChars": "never" 不允许语句末尾有分号,即使下一行以 [(/+- 开头,只要不造成 ASI 危险。

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

always

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

js
/*eslint @stylistic/semi: ["error", "always"]*/

var name = "ESLint"
object.method = function() { // ... }
class Foo { bar = 1
}
不正确

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

js
/*eslint @stylistic/semi: "error"*/

var name = "ESLint";

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

class Foo {
    bar = 1;
}
正确

omitLastInOneLineBlock

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

js
/*eslint @stylistic/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 } 选项时,此规则的额外正确代码示例

js
/*eslint @stylistic/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" 选项时,此规则的不正确代码示例

js
/*eslint @stylistic/semi: ["error", "never"]*/

var name = "ESLint"
;
object.method = function() { // ... }
;
class Foo { bar = 1
;
}
不正确

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

js
/*eslint @stylistic/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" } 选项时,此规则的额外不正确代码示例

js
/*eslint @stylistic/semi: ["error", "never", { "beforeStatementContinuationChars": "always"}] */
import a from "a"
(function() { // ... })()
不正确

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

js
/*eslint @stylistic/semi: ["error", "never", { "beforeStatementContinuationChars": "never"}] */
import a from "a"

;
(function() {
// ... })()
不正确

何时不使用它

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

TypeScript 特定

ts/semi

另请参见 @stylistic/ts/member-delimiter-style 规则,它允许您指定 typeinterface 成员的分隔符。