QA@IT

JavaScript モジュールパターン実装時のカッコの位置

11099 PV

JavaScript モジュールパターンについて勉強中で、WEB、書籍を見ているのですが、
即時呼出関数式のカッコの位置について、参照元によりバラバラで、どれが正しいのか(一般的なのか)
迷っています。
コード1, コード2 のパターンが見受けられるのですが、そもそもコード3のパターンでも正しく動作します。
(以下の3パターンで全て動作結果は同じです。)

違いについてご教示いただければと思います。

コード1

var fooModule = (function() {
  return {method1: function() {console.log("method1");}};
})();
fooModule.method1();

コード2

var fooModule = (function() {
  return {method1: function() {console.log("method1");}};
}());
fooModule.method1();

コード3

var fooModule = function() {
  return {method1: function() {console.log("method1");}};
}();
fooModule.method1();

回答

返信遅くなりました。
無名関数、即時関数は理解しているつもりです。

具体的な例示をしていなかったので... Functional Programming in JavaScript
邦題=JavaScript関数型プログラミング(ISBN978-4-295-00113-3)
66-67pのサンプルプログラムのに関する疑問からの投稿でした。
上記のサンプルは海外版オンラインで一部確認できます。
https://dpzbhybb2pdcj.cloudfront.net/atencio/Figures/051fig01_alt.jpg

こちらのコード、の最終行が、
}(MyModule || {}));
となっていますが、
即時関数なら(最後に引数を伴っているので即時関数ならですよね。)
})(MyModule || {});
が正しいのか?と思いました。
実行するとどちらでも同じ結果でしたので、疑問に感じていました。

その後、色々別でも調べて、JavaScriptの場合、
行頭にfunctionがあるとfunction文
そうでなければ、functionリテラルと判断されるようで、
どちらかというと、functionの頭を小括弧で囲むこと自体が大切なだけなのかな?
と思っている次第です。

いかがでしょうか?

余談...High Sierraの日本語入力が言うことをきかず、誤字があるかもしれません。

編集 履歴 (0)
  • 質問者さんは回答欄に書書かないというのがこのサイトの流儀のようです。(回答と混ざって何が何だか分からなくなるから)。回答に対するコメントとして書いてください。コメント欄に書ききれなければ、最初の質問欄に追記することもできるはずです(その際はコメント欄にその旨一言書いて) -
  • 質問者さんが上の回答欄に書いた分はカット&ペーストで質問欄に追加して、上の回答欄には「質問欄に移動」とだけ書いていただくわけにはいきませんか? 今のままでは追加の回答がしづらいです。 -
  • 自分の回答欄に追記しました。 -

小括弧の使い方が普通ではないように思います。

以下の記事で言う「無名関数」と「即時関数」での小括弧の使い方がごっちゃになっていませんか?

【JavaScript】無名関数と即時関数?関数パターンを理解してメンテナブルなソースに!
http://unitopi.com/js-function/

質問者さんのアップされたコード例を上の記事の分類に従って書き換えると以下のようになると思いますが。

無名関数

var fooModule = function () {
    return {
        method1: function () { console.log("method1"); },
        method2: function () { console.log("method2"); },
        method3: function () { console.log("method3"); }
    };
};

var m = new fooModule();
m.method1();
m.method2();
m.method3();

即時関数

(function () {
    (function method4() { console.log("method4"); })();
})();

実行結果

results.jpg

------------ 2017/10/1 追記 ------------

上の回答が的外れだったようですみません。

「モジュールパターン」の話はちょっと置いておいて、即時関数の書き方について書きます。

基本的には以下の記事に書いてあることですが・・・ (自分がググって調べた限りでは、この記事が一番詳しくかつ信頼できそうでした)

Immediately-Invoked Function Expression (IIFE)
http://benalman.com/news/2010/11/immediately-invoked-function-expression/

まず以下のケース、

(function () {/* code */})();
(function () {/* code */}());

については、function () {/* code */} が小括弧 (grouping operator) で囲われているので JavaScript パーサーはそれを関数式 (function expression) と解釈する。関数式の後ろに小括弧 (invocation operator) が付与されているので実行 (invoke) される。

そして、

var f = function () {/* code */}();

については、function () {/* code */} を小括弧 (grouping operator) で囲わなくても、JavaScript パーサーはそれを関数式であると解釈するので、小括弧 (invocation operator) だけを付与すれば実行される。

・・・ということになり、いずれも即時間数の書き方として有効(つまりどれも正しい)ということのようです。

どれが一般的かは、個人の好みとか組織のコーディングルールにもよると思いますが、var f = function ... というような場合でも、即時関数であることを明確に示すために、小括弧 (grouping operator) で囲うのがよさそうです。

上に紹介した記事の「An important note about those parens」と「A final aside: The Module Pattern」にそのことが書いてあります。

invocation operator の括弧を grouping operator の括弧の中に入れるか / 外に出すかについては、これも紹介した記事に書いてありますが、Douglas Crockford さんは括弧の中に入れるのを推奨しているそうです。

彼が作った JSLint ( http://jslint.com/ ) にかけてみると、後者は以下の警告メッセージが出ますが、それが理由のようです。

"Wrap an immediate function invocation in parentheses to assist the reader in understanding that the expression is the result of a function, and not the function itself."

上に紹介した記事の著者もそのような書き方をしています。

編集 履歴 (2)
ウォッチ

この質問への回答やコメントをメールでお知らせします。