- ベストアンサー
クロージャーの利点が理解できない
クロージャーの利点はグローバル変数を使わずにコードがかけると認識しているのですが、 http://dqn.sakusakutto.jp/2009/01/javascript_4.html だとcがグローバルじゃないけどfがグローバル変数なんで結局グローバル変数が存在する事になって意味がないような気がします。 他のサンプルでもだいたいこんな形です。 それでもクロージャー使う方がいいのでしょうか? ご教示頂けると幸いです。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
実際にクロージャを使わない実装をしてみると、わかりやすいと思います。 (1) クロージャを使わない例 https://ideone.com/QcpkE (2) クロージャを使った例 https://ideone.com/DoWf2 (2) ではローカル変数 xがプライベート変数扱いとなり、外部からアクセスできなくなります。 var x; を他で宣言しても干渉しません。 一方、(1) では他のコードで var x; を宣言することで名前空間の衝突が発生します。 グローバル変数 x を宣言しない事は勿論、x に不正な値が代入されないように注意しなければなりません。 > クロージャーの利点はグローバル変数を使わずにコードがかけると認識しているのですが、 それも利点の一つですが、本質ではないと思います。 上のサンプルではどちらのコードでも匿名関数で括ればグローバル変数は宣言されません。ただし、変数 x のスコープは異なります。 グローバル変数を宣言したくないのなら、全コードを匿名関数で括ってやり、更に一段階深いクロージャにすればいいのです…。
その他の回答 (5)
- Chaire
- ベストアンサー率60% (79/130)
// (1) function combine (f, g) { return function () { return g(f()); }; } function A() { alert('A'); } function B() { alert('B'); } function C() { alert('C'); } var p = combine(A, B); p(); // 'A', 'B' var q = combine(B, C); q(); // 'B', 'C' 関数と関数を組み合わせ、新しい関数を作り出しています。もし、これに条件を付けて「~のときは A と B」「~のときは B と C」のように関数を生成できたら、ひょっとすると「目的の動作をする関数を、自動的に作る関数」ができ上がるのではないでしょうか。 // (2) function A (x, y, z) { return x + y + z; } var p = A(1, 2, 3); // 6 言うまでもなく、x と y と z を足す関数です。しかし、「今は x と y のセットだけできるが、z が何か分からない」という場合もあるかもしれません。 function B (x, y) { return function (z) { return A(x, y, z); }; } var q = B(1, 2); q(3); // 6 こうすれば、先に x と y だけセットしておき、好きなタイミングで z をセットして結果を得られます。 --- 高階関数、部分適用、遅延評価あたりをキーワードにクロージャ(関数閉包)の使い道を考えてみて下さい。やろうと思えば制御文の多くがコードから消えます。 しかし、現状の JS エンジンではかなり遅くなるでしょう。また、No.4 で指摘されているように、メモリ管理に関する不安材料も若干あります。ですから多用は勧めません。やり過ぎると解せないスパゲッティになるのは、グローバル変数と大差ないです。 とは言え、一度はクロージャの使い道を模索して下さい。その後、元の書き方に戻るにしても、コードの見え方が違うと思います。
お礼
ありがとうございました。 非常に参考になりました。やはり頭だけで理解しようとせず書かないとダメですね。
- fujillin
- ベストアンサー率61% (1594/2576)
私もよくわかっていないので、かならずしも正しくはないと思いますが… >クロージャーの利点はグローバル変数を使わずにコードがかけると >認識しているのですが 変数化しなくてすむというのは匿名関数を利用することによるもなので、説明用のサンプルがとても簡単なものにしているためにそう見えるだけではないでしょうか? クロージャ的にすると、その環境も保持されるというのが一番大きなメリットではないでしょうか? 変数の引渡しや管理をしなくても済むので便利という面もあります。 簡単な例はNo1様が提示なさっているので、応用例にしてみると・・・ 以下のように、アニメーションで複数の要素を同時に扱おうとするときに便利とか… (例では処理関数を並行して実行させていますが、同じことをやるにしても、目的の機能を持つプロトタイプを作成しておいて、複数の実体化すると言う方法もあります) >それでもクロージャー使う方がいいのでしょうか? 必要を感じなければ使わない方が良いみたい。 (クロージャを使うことが、メモリーリークの原因になりやすいようなので) クロージャなしに書き直してみれば、利点がわかるかと思います。 (全角空白は半角に) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="ja"> <head><title>sample</title> <meta http-equiv="Content-Style-Type" content="text/css"> <meta http-equiv="Content-Script-Type" content="text/javascript"> <style type="text/css"> div div { width:100px; float:left; margin:10px; overflow:hidden; } </style> <script type="text/javascript"> <!-- function test(evt){ var t = evt.target || evt.srcElement; if (t.nodeName != "DIV" || t.className.match(/\bactive\b/)) return; var hh = t.clientHeight; t.className += " active"; slide(t, hh, 0, function(){ slide(t, 0, hh, function(){ t.className = t.className.replace(/ active$/, ""); }); }); } function slide(node, start, end, callback){ var s = node.style, f = start<end; var h = start, step = f?2:-6;; var intervalId = setInterval(function(){ h += step; if ((f && end<h) || (!f && end>h)) h = end; s.height = h + "px"; if (h==end) { clearInterval(intervalId); node = s = null; if (callback) callback(); } }, 30); } //--> </script> </head> <body> <div onclick="test(event)" style="width:400px;"> <div style="height:150px; background-color:red;"></div> <div style="height:200px; background-color:blue;"></div> <div style="height:250px; background-color:green;"></div> </div> </body> </html>
お礼
ありがとうございました。非常に参考になりました。
- 神崎 渉瑠(@taloo)
- ベストアンサー率44% (1016/2280)
変数名の重複によるバグを予防できます。
- babu_baboo
- ベストアンサー率51% (268/525)
ていせい。 > ぐろーばるへんすうはつかわない を、 かうんとするへんすうは、ぐろーばるにしない
- babu_baboo
- ベストアンサー率51% (268/525)
もんだい、その1 あるかんすうが、よばれるたびに、かうんとし、そのあたいをかえす、かんすうをかきなさい。 ただし、ぐろーばるへんすうは、つかわないものとする。 かうんとのしょきちは、さいしょにじゆうなすうちからはじめられるものとする。
お礼
コードまで示して頂きありがとうございました。 >> クロージャーの利点はグローバル変数を使わずにコードがかけると認識しているのですが、 >それも利点の一つですが、本質ではないと思います。 これで、何かスッキリしたというかふっきれた気持ちになりました。