jQueryプラグインの先頭にセミコロンがある理由
jQueryプラグインの先頭にセミコロンがある理由を調べてみました。
1.「jQueryプラグインの先頭にセミコロン」とは?
例えば、レスポンシブ対応で画像を拡大表示できる「SuperBoxプラグイン」のコードは次のようになっています。
;(function($) {
$.fn.SuperBox = function(options) {
var superbox = $('<div class="superbox-show"></div>');
var superboximg = $('<img src="" class="superbox-current-img">');
…中略…
});
};
})(jQuery);
1行目の行頭にセミコロンがついています。
;(function($){
直感的に「エラー防止用かな?」と思って調べてみたらそのとおりだったのですが、以下調べたことについて解説します。
2.セミコロンの省略と自動補完について
このエントリーの本題ではないので詳細は割愛しますが、JavaScriptはセミコロンの省略が可能で、省略した場合、処理系でセミコロンの自動補完を行ってくれるようです。
たとえば次のようなコードは正常に動作します。
var foo = "foo"
console.log(foo)
var bar = "bar"
console.log(bar)
すべての改行で補完されるわけではないようですが、ここでお伝えしたいのは「セミコロンが省略されたコードも存在する」ということです。
なお、Google JavaScript Style Guide 和訳ではセミコロンを省略してはいけないように記載されています。
常にセミコロンを使います. コードのセミコロンを省き, セミコロンの挿入を処理系に任せた場合, 非常にデバッグが困難な問題が起こります. 決してセミコロンを省くべきではありません.
3.jQueryプラグインの先頭にセミコロンがある理由
jQueryプラグインはひとつの独立したファイルとして扱うこと以外に、パフォーマンス向上などのため、他のJavaScriptコードと混在させて1つのファイルにまとめるケースもあると思います。
で、混在させて、さらに圧縮・難読化などでコードを1行にしたときに直前のコードにあるべきセミコロンがなかった場合、エラーになる可能性が高いです。
例えば、
console.log(bar)
の後方にjQueryプラグイン
(function($) {
…後略…
を貼り付けて1行にすると、
console.log(bar)(function($) { …後略…
となり、処理系で補完されないため、実行時にエラーとなります。
そのような不測の事態を発生させないようにするため、jQueryプラグインの先頭にセミコロンをつけているようです。
console.log(bar);(function($) { …後略…
4.予期しない動作になるサンプル
3項では1行化を行ったケースについて触れましたが、1行化を行わない(=改行が含まれる)場合でもセミコロンがないことにより予期しない動作になることがあります。
jQueryプラグインの先頭にあるセミコロンは、そのケースも考慮しているように思われます。
その具体的なケースについて、「Google JavaScript Style Guide 和訳」のサンプルを使って解説します。
「jQuery で ;(function () ...と、セミコロンで始めることがあるのはなぜか」で別のサンプルによる解説を参考にさせていただいてますが、認識誤りがありましたらどこかでつぶやいてください。
「Google JavaScript Style Guide 和訳」には次のようなサンプルが掲載されています。
MyClass.prototype.myMethod = function() {
return 42;
} // ここにセミコロンがない
(function() {
// この一時的なブロックスコープで初期化処理などを行う
})();
このコードについて次のように解説されています。
JavaScript Error: はじめの 42 を返している無名関数が, 2つ目の関数を引数にとって実行されてしまい, 42 を関数として呼び出そうとしてエラーになる.
まず、前半の「はじめの 42 を返している無名関数が, 2つ目の関数を引数にとって実行されてしまい」までを解説します。
理解を容易にするため、コメントの一部を省略して次のようにします。
MyClass.prototype.myMethod = function() {
return 42;
}
(function() {
// ...
})();
2項でセミコロン補完の話をしましたが、このコードの3行目でセミコロンは補完されず、次のコードとして解釈されます。
MyClass.prototype.myMethod = function() {
return 42;
}(function() { // ... })();
これで無名関数は即時関数「 (function(){...})();」として解釈されてしまうようです。
分かりにくいのですが、即時関数は定義部分のカッコを省略できるらしく、このコードで定義部分というのは「function() { return 42; }」が該当します。
つまり、上記のコードで省略されたカッコをつけると、
MyClass.prototype.myMethod = (function() {
return 42;
})(function() { // ... })();
となります。
そして、この即時関数は「function() { // ... }」を引数として実行してしまいます、というのが前半の「はじめの 42 を返している無名関数が, 2つ目の関数を引数にとって実行されてしまい」の部分になります。
後半の「42 を関数として呼び出そうとしてエラーになる.」は、即時関数が実行されて「return 42;」で42を返却すると、イメージとしては、
MyClass.prototype.myMethod = (function() {
return 42;
})(function() { // ... })();
の
(function() {
return 42;
})(function() { // ... })
の部分が実行され、その返却値と元のコードにある後のカッコをあわせて
42();
のような形で実行されるのではないかと思います。
最後のカッコがなければ、実行結果の42はMyClass.prototype.myMethodに代入されるようです。
参考サイト「Dangers of anonymous function closures」にある次のコードでより動作が明確になると思いますので試してみてください。
var foo = function(bar) {
console.log("foo");
return bar;
}
(function(){
console.log("bar")
})();
このコードを実行すると、「foo」「bar」の順で文字列がコンソールに出力されます。
5.参考サイト
参考サイトは以下です。ありがとうございました。
- 7.9.1 自動セミコロン挿入規則 (Rules of Automatic Semicolon Insertion)
- jQuery で ;(function () ...と、セミコロンで始めることがあるのはなぜか
- Dangers of anonymous function closures
- 即時関数の定義をかこう方のカッコは省略できることがある
- Google JavaScript Style Guide 和訳
- jQuery+ajaxでモーダルのコンテンツを取得する方法
- jQueryでパスワードの表示・非表示を切り替えるサンプル
- jQueryでファイル選択時にプレビュー表示する方法
- ラジオボタンをjQueryで解除する方法
- テーブルのセルをポイントすると行と列を反転表示するjQueryプラグイン「Table Hover」
- jQueryで親ページからiframeのスクロールバーを非表示にする方法
- jQueryのカスタムビルドが簡単にできるサービス「jQuery Builder」
- jQueryでCSSをまとめて書き換える方法のまとめ
- 親ページからiframe内の要素にCSSを適用させる方法
- jQueryで要素を削除する方法のまとめ
- jQueryでテキストを追加するたびにスクロールさせる方法
- jQuery.ajax()でファイルをアップロードする方法
- preventDefault()で無効にしたイベントを有効にする方法
- jQueryで要素数を取得する方法のまとめ
- jQueryやJavaScriptでパスワードフィールドの文字を表示する方法