semi
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 字符总是结束一个语句(就像分号一样),除非以下情况之一为真
- 该语句具有未关闭的括号、数组字面量或对象字面量,或者以其他非有效方式结束语句。(例如,以
.或,结尾。) - 该行是
--或++(在这种情况下,它将递减/递增下一个标记。) - 它是
for()、while()、do、if()或else,并且没有{ - 下一行以
[、(、+、*、/、-、,、.或其他只能在单个表达式中的两个标记之间找到的二元运算符开头。
规则详细信息
此规则强制一致使用分号。
选项
此规则有两个选项,一个字符串选项和一个对象选项。
字符串选项
"always"(默认)要求语句末尾有分号"never"不允许语句末尾有分号(除非用于区分以[、(、/、+或-开头的语句)
对象选项(当 "always" 时)
"omitLastInOneLineBlock": true不允许在花括号(以及块的内容)位于同一行的块中使用最后一个分号"omitLastInOneLineClassBody": true不允许在花括号(以及类体的内容)位于同一行的类体中使用最后一个分号
对象选项(当 "never" 时)
"beforeStatementContinuationChars": "any"(默认)忽略语句末尾的分号(或缺少分号),如果下一行以[、(、/、+或-开头。"beforeStatementContinuationChars": "always"要求语句末尾有分号,如果下一行以[、(、/、+或-开头。"beforeStatementContinuationChars": "never"不允许语句末尾有分号,即使下一行以[、(、/、+或-开头,只要不造成 ASI 危险。
注意:beforeStatementContinuationChars 不适用于类字段,因为类字段不是语句。
always
使用默认 "always" 选项时,此规则的不正确代码示例
/*eslint @stylistic/semi: ["error", "always"]*/
var name = "ESLint"
object.method = function() {
// ...
}
class Foo {
bar = 1
}使用默认 "always" 选项时,此规则的正确代码示例
/*eslint @stylistic/semi: "error"*/
var name = "ESLint";
object.method = function() {
// ...
};
class Foo {
bar = 1;
}omitLastInOneLineBlock
使用 "always", { "omitLastInOneLineBlock": true } 选项时,此规则的额外正确代码示例
/*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 } 选项时,此规则的额外正确代码示例
/*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" 选项时,此规则的不正确代码示例
/*eslint @stylistic/semi: ["error", "never"]*/
var name = "ESLint";
object.method = function() {
// ...
};
class Foo {
bar = 1;
}使用 "never" 选项时,此规则的正确代码示例
/*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" } 选项时,此规则的额外不正确代码示例
/*eslint @stylistic/semi: ["error", "never", { "beforeStatementContinuationChars": "always"}] */
import a from "a"
(function() {
// ...
})()使用 "never", { "beforeStatementContinuationChars": "never" } 选项时,此规则的额外不正确代码示例
/*eslint @stylistic/semi: ["error", "never", { "beforeStatementContinuationChars": "never"}] */
import a from "a"
;(function() {
// ...
})()何时不使用它
如果您不想以任何特定方式强制使用(或省略)分号,则可以关闭此规则。
TypeScript 特定
ts/semi
另请参见 @stylistic/ts/member-delimiter-style 规则,它允许您指定 type 和 interface 成员的分隔符。