ここから本文です

JavaScriptのクロージャはどういった場合に利用するのでしょうか。どんな場合にメ...

app********さん

2013/1/2421:22:45

JavaScriptのクロージャはどういった場合に利用するのでしょうか。どんな場合にメリットがあるのか教えて頂けないでしょうか。具体的なコードを示して頂けるとありがたいです。

この質問は、活躍中のチエリアン・専門家に回答をリクエストしました。

閲覧数:
2,178
回答数:
3
お礼:
100枚

違反報告

ベストアンサーに選ばれた回答

ris********さん

リクエストマッチ

2013/1/2606:44:10

計算機科学の理屈上では、関数(引数、戻り値)さえあれば、あらゆる計算が可能です。変数なんていらないんです。

function F (x) { // 変更される値は引数で与えられる
const a = 1; // 分かりやすさのために定数は可、ただし再代入はできない
return x + a;
}

F(1); // 2

上の F は、与えられた数字に必ず 1 を足して返す関数ですね。関数 F は、引数 x に対して、必ず 1 つの結果を返します。プログラムの結果が予測しやすくなると同時に、エラーの原因も瞬時に分かるようになります。こういうのを参照透過性と言ったりします。

でも、上の定数 a を変更したい場合もあるでしょう。そんなときは関数 F を作る関数 G を作れば良い。

function G (a) {
return function F (x) {
return x + a;
}
}

const F1 = G(1); // 1 を足す関数
F(1); // 2

const F2 = G(2); // 2 を足す関数
F(1); // 3

作られた関数 F は、関数 G に与えられた引数 a を参照することができます。このように、関数と外部変数のセットのことをクロージャ(閉包)と呼びます。

このように、JavaScript のクロージャは、典型的には「関数を作る関数」として実現されることが多いです。最近の JavaScript には、Array メソッドなど「高階関数」をとるものも増えていますので、「関数を作る関数」をぜひ覚えて下さい。

ただ、世間的に言われている「いわゆるクロージャ」は、上の性質を利用して変数を外に漏らさないことだけを意味したり、関数リテラル(実際はリテラルではありませんが)をクロージャと呼んでいたり、かなり混乱して使われています。

この質問は投票によってベストアンサーに選ばれました!

ベストアンサー以外の回答

1〜2件/2件中

並び替え:回答日時の
新しい順
|古い順

fuk********さん

2013/1/2522:50:00

メリット以上にデメリットも理解しましょう。

クロージャはメモリ効率が悪いので、
Mozilla Foundation では極力クロージャになることを避けることを推奨しています。

以下参照
https://developer.mozilla.org/ja/Core_JavaScript_1.5_Reference/Func...
>入れ子の関数とクロージャ
...
> このように効率が悪いので、可能な限りクロージャを避けてください。
> すなわち、可能な限り関数を入れ子にするのは避けてください。

b0a0aさんの例示もメモリをつかんで離さないのを利用した例ですね。
自分ならクロージャを避けてオブジェクトで共有してグローバル変数の汚染を
防ぎますね。

b0a********さん

リクエストマッチ

編集あり2013/1/2616:49:43

例えば押すと「何番目のボタンが押されました」と表示されるボタンを10個作るとします

for(var i=1;i<=10;i++){
button=document.createElement("button")
button.textContent=i
button.addEvenyListener("click",function(){alert(i+"番目のボタンが押されました")})
document.body.appendChild(button)
}

この例は間違いです全てのボタンのイベントハンドラ内のiが属するスコープはforのiと同じなので、
どのボタンを押しても「11番目のボタンが押されました」と表示されてしまいます
適切に動作させるためにはスコープをハンドラ内に留めないといけません
こういう時はletが便利です

for(let i=1;i<=10;i++){
button=document.createElement("button")
button.textContent=i
button.addEvenyListener("click",function(){alert(i+"番目のボタンが押されました")})
document.body.appendChild(button)
}

しかしletは古い環境では使えないので、その他の解決策の1つとしてクロージャがあります

for(var i=1;i<=10;i++){
button=document.createElement("button")
button.textContent=i
button.addEvenyListener("click",(function(i){
return function(){alert(i+"番目のボタンが押されました")}
})(i))
document.body.appendChild(button)
}

これは

(function(i){
return function(){alert(i+"番目のボタンが押されました")}
})(i)

でその時のiの値を固定しています
クロージャは要は変数を保持した関数なのです
これによりグローバル変数の汚染を防げます


----補足----
メモリの話がありますがそんなのは微々たるものです
ボタンを何万個も作ったり何日間も起動し続けるアプリケーションを作るので無ければ心配はいりません

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

Q&Aをキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問は選択されたID/ニックネームのMy知恵袋で確認できます。

不適切な投稿でないことを報告しました。

閉じる