[JavaScript] セミコロンをつければ絶対安心できるのか?;


はじめに

こちらの記事 を読んで、改めてJavaScriotの ; について気になったので調べてみました。

結論

私が思ったより安心じゃなかった。

セミコロンありのスタイルでも、下記のように予期せぬセミコロンの挿入が起こってしまうパターンがあります。

function f() {
    return
        {
          foo: 'foo'
        };
}

f(); // undefined

セミコロンに関することは参考にさせていただいたセミコロンに関する ESLint ルールという記事に全部書いてありました

以下の内容はリンク先の記事に(個人的な感想以外)書いてあることなので、ぜひそちらを参考にしてください!

ASI(Auto Semicolon Insertion)

JavaScript の改行箇所で構文エラーがあった際にセミコロンにを自動的に補い再解釈する言語機能のことですが、結局のところこいつが曲者で、初心者や他言語からJavaScriptを触るようになった方が理解し難く感じる要因でしょう。

ECMAScript の言語仕様に ASI 利用に関する警告が ES2019 から追加 されています。

ASIの振る舞いで気をつけるべきこと

予期せぬセミコロン挿入の欠損

console.log(4) // > 4
['foo', 'bar'].forEach(el => console.log(el)) // > Uncaught TypeError: Cannot read property 'bar' of undefined

console.log(4)['foo', 'bar'].forEach が構文上正しいと解釈され、セミコロンの自動挿入が起こりません。, がカンマ演算子として解釈されるため、 bar が未定義というエラーが出ます。

このパターンは実行してみてエラーで気づくことができそうです。また、TypeScriptなら型チェックで気づけます。

予期せぬセミコロン挿入

function f1()
{
    return
        2020;
}

function f2()
{
    return
        {
          foo: 'foo'
        };
}

function f3()
{
    return
        ({
          foo: 'foo',
          bar: 'bar'
        });
}

f1(); // undefined
f2(); // undefined
f3(); // undefined

こちらが先に上げたパターンと同じですが、 return のあとにセミコロンが自動挿入され、改行後の値が返されません。

また、f2の関数には Object そのものが存在していません。
{ foo: 'foo' } の部分は Object ではなく、ブロックとして解釈されてしまっています。 foo:fooラベル構文です。意味のないブロックですが、文法そのものに影響しないので無視されています。

C#とか Allman brace style が推奨の言語から来た方は引っかかる?(多くの場合はそんなことないでしょうが)
Lint などがない場合は間違って改行していた場合気づかないかもしれませんね。

ちなみに、ラベル構文の後にカンマをつけることはできないため以下は構文エラーになります。

function f() {
    return
        {
          foo: 'foo',
          bar: 'bar
        };
}

// > Uncaught SyntaxError: Unexpected token :

まとめ

今回調べてみて結局のところ、セミコロンありなのかなしなのかは好みの問題という域を出ないように感じました。
それよりも、ASIの独特の動きを理解して(といってもそんなに多くの動作は無いように思います。)、Lint や Formatter などのツールをしっかり活用することで、こういった問題を起こさない様にすることの方が重要だと思います。

特に、ESLintやPrettierを使う際にはJavaScript Standard Styleのようなプリセットを利用し、極力自力で設定しないことが、このような罠にハマらないために大切です。(JavaScript Standard Styleにはセミコロンあり版が存在します)

また、可読性についても一長一短で、個人によるところが大きいと思います。(私はセミコロンレスの方が見やすく感じます)

参考

セミコロンをつけ忘れただけなのに...【JavaScript】

セミコロンに関する ESLint ルール

To Semicolon, Or Not To Semicolon;

Using Semicolons? Never Use Them!

JavaScript Standard Style