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 中引入。