JavaScriptにおけるIIFEの落とし穴
二つのコード片を見てみましょう。
一つ目:
let result = 1
+function() {
return 2;
}();
console.log(result);
二つ目:
let result = 1;
+function() {
return 2;
}();
console.log(result);
これらのコード片はほとんど同じですが、実行すると結果が異なります。
一つ目のコードはコンソールに数字3を出力し、
二つ目は数字1を出力します。
この違いが生じた理由は、最初の行の末尾にセミコロンがあるかないかです。
あなたはこう尋ねるかもしれません:JavaScriptではセミコロンは必須ではないのでは?と。 実際のところ、それは完全に正しくありません。実際に何が起きているのかを理解しましょう。
最初のコードは次のように書き換えることができます:
let result = 1 + function() {
return 2;
}();
console.log(result); // 3 を出力
これで明らかになったように、1に即時関数呼び出しの結果、つまり2が加算されています。したがって最終結果は3になります。
一方、1の後にセミコロンを置くと、インタープリターはコードを別の方法で解釈します:
// 最初の文:
let result = 1;
// 二つ目の文:
+function() {
return 2;
}();
// 三つ目の文:
console.log(result); // 1 を出力
つまり、変数への代入と即時関数呼び出しは別々の文になります。 そしてこれはセミコロンの有無によって決まるのです!
この場合、即時関数呼び出しは事実上何もせず、単に数字2を無意味に返しているだけで、変数resultには何の影響も与えません。
では、そもそもなぜJavaScriptでセミコロンを書かなくても良いのでしょうか。 セミコロンなしの次のようなコードを見てみましょう:
let result = 1 // result には 1 が書き込まれる
let test = 2 // test には 2 が書き込まれる
これは正しく動作します。なぜならインタープリターが各行の末尾に自動的にセミコロンを挿入するからです。
しかし、次のコードを見てください:
let result = 1
+ 2; // result には 3 が書き込まれる
今度は、最初の行の末尾にセミコロンは自動的に挿入されません。なぜならインタープリターは、2行目のコマンドが1行目のコマンドの一部であると理解するからです。
しかし、もし私たちが自分でセミコロンを置けば、結果は全く異なります:
let result = 1; // result には 1 が書き込まれる
+ 2; // この文は何もしないが、エラーも発生しない
つまり、インタープリターは、次のコマンドが前のコマンドの一部でない場合にのみ、自動的にセミコロンを置くのです。
そして今、このコードを見てください:
let result = 1
+function() {
return 2;
}();
console.log(result);
確かに、2行目は単に1行目のコマンドの続きであり、インタープリターは自動的にセミコロンを挿入しません。 これが、最初の行の末尾に自分でセミコロンを書くと結果が全く異なる理由です。 これは、問題を避けるために、必要な場所には常にセミコロンを置くのが最善であることを示しています。