semi
要求或禁止使用分号代替 ASI
此规则报告的一些问题可以通过 --fix
命令行 选项自动修复
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
字符总是结束一个语句(就像分号一样),除非以下情况之一为真
- 语句有一个未闭合的括号、数组字面量或对象字面量,或者以其他无效的方式结束语句。(例如,以
.
或,
结尾。) - 该行是
--
或++
(在这种情况下,它将递减/递增下一个 token。) - 它是一个
for()
、while()
、do
、if()
或else
,并且没有{
- 下一行以
[
、(
、+
、*
、/
、-
、,
、.
或其他只能在单个表达式中的两个 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 中引入。