跳至内容

@stylistic/js/

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/js/semi: ["error", "always"]*/

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

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

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

var name = "ESLint";

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

class Foo {
    bar = 1;
}
正确

omitLastInOneLineBlock

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

js
/*eslint @stylistic/js/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/js/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/js/semi: ["error", "never"]*/

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

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

js
/*eslint @stylistic/js/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/js/semi: ["error", "never", { "beforeStatementContinuationChars": "always"}] */
import a from "a"
(function() { // ... })()
不正确

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

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

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

何时不使用它

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