🧭

JavaScriptにセミコロンは入れるのか?入れないのか?

2022/08/14に公開

結論

  • どちらでもいい
  • セミコロン付けても付けなくても落とし穴はある
  • ESLintを利用することで落とし穴を検知できる
  • 私はセミコロンつけない派

自動セミコロン挿入とは

自動セミコロン挿入(automatic semicolon insertion)

  • この仕組みのおかげでセミコロンを使わなくてもコードを書くことができ、コンパイラが行末を察してセミコロンを挿入してくれる
  • 自動セミコロン挿入のしくみはECMAScriptで規定されており、自動セミコロン挿入はJavaScriptエンジン間で可搬性がある
  • 自動セミコロン挿入には落とし穴があり、ルールを理解しておく必要がある

第1のルール:セミコロンが挿入されるのは、"}"トークンの前か、改行の後か、プログラムの末尾だけ

{ 1
2 } 3

// 上記の文は、 ASI によって次のように変換される

{ 1
;2 ;} 3;

第2のルール:セミコロンが挿入されるのは、次の入力トークンを字句解析できないときだけ

セミコロン挿入されないケース

a = b
(f());

// これは1個の文として正しく解析できるので、次のよう変換される

a = b(f());

セミコロン挿入されるケース

a = b
f();

// これは2つの別々の文として解析される
// なぜなら次のように解釈したら解析エラーとなるから
// a = b f();

a = b;
f();

このルールには落とし穴があり、セミコロンを省略できるかできないかを判断するために、次の文の始まりに注意する必要がある

問題になる記号は(,[,+,-,/の5つ。
もし次の文が問題となる5つの記号のどれかであれば、セミコロンは挿入されない。

[の落とし穴

a = b
['🍎', '🍌', '🍈'].forEach((key) => {
  console.log(fluits[key]['price']);
);

// 後続の文が [ で始まるので、1つの文として解析される

a = b['🍎', '🍌', '🍈'].forEach((key) => {
  console.log(fluits[key]['price']);
);

/の落とし穴

a = b
/Error/i.test(str) && fail();

// 以下のように変換される

a = b / Error / i.test(str) && fail();

必ずセミコロンを記述すれば無問題?

実はそうでもない。
構文解析でエラーにならない部分もコンパイラが強制的にセミコロンを挿入するケースがある。

return
{ };

// これは次の3つの文として解析されてしまう

return;
{ }
;

セミコロンが挿入される場所(<;>)は次の通り

  • expr <;> ++expr <;> --
  • continue <;> lbl
  • break <;> lbl
  • return <;> expr
  • throw <;> expr
  • yield <;> expr
  • yield <;> * expr
  • (param) <;> => {}
  • async <;> functionasync <;> prop()async <;> function*async <;> *prop()
  • async <;> (param) <;> => {}

第3のルール:セミコロンがforループ頭部の区切りとして挿入されることはない

forループではセミコロンを明示的に書く必要がある

for (let i = 0 // parse error
    i < n
    i++) {
    // 何かしらの処理
}

// 明示的にセミコロンを書く必要がある
for (let i = 0 ; i < n ; i++) {
    total *= i
    // 何かしらの処理
}

どっちがいいの?

メリット デメリット
セミコロンあり 落とし穴は少ない 最近のセミコロンを書かない言語から見ると古臭く見える
セミコロンなし コードがすっきりする
タイピング量が減る
セミコロン挿入のルールを知っていないと危険が多い

TC39ではどうなっているの?

TC39では入れるか入れないかを定義していない。
世間にはセミコロンを使っていないJavaScriptコードは山ほどあるので、セミコロンを使うのが正しくて、セミコロンが無くても動くのはたまたま動いているだけですと言うのは厳しいと思われる。

どうすれば良い?

EsLintを使用し、意図しない動作になる箇所があれば警告を出す。

セミコロンを常に書く場合はno-unreachableルール
no-unreachable

セミコロンを省略する場合はno-unexpected-multilineルール
no-unexpected-multiline

ESLintを利用することで意図しない動作は検出できます。
セミコロン入れる派 or セミコロン入れない派、どちらも楽しくコーディングしていきましょう!

Discussion