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
成员的分隔符。