jiichan.com

PROGRAMMING

クロージャの使いどころ

理解に苦しんだクロージャですが、クロージャの定義みたいなもの?は解ったような気がします。
ただ、そのクロージャをどんな時に使うのかというところが未だピンと来ていません。 その辺のところを考えて見ます。

マニュアル本や、いろいろなサイトで見かけるクロージャのサンプル

次の例は、マニュアル本や、いろいろなサイトで紹介されているクロージャの例です。


function closure(num){
	var counter = num;

	return function (){
	  counter++;
	  document.write(counter + "<br>");
	};
}

var func1 =  closure(0);
var func2 =  closure(100);

func1();	// counterの値=1
func2();	// counterの値=101
func2();	// counterの値=102
func2();	// counterの値=103
func1();	// counterの値=2
func1();	// counterの値=3

関数を呼び出す(実行)する度にインクリメントされた数字を返すというもので、 このサンプルを見てクロージャとはこういうものかと理解しました。

1. 関数の中に関数 2. 外側の関数の戻り値として内側の関数を返している 3. 内側の関数から外側の関数のローカル変数を参照している 4. 参照している変数の値を保持している
この中でメリットと思われるのは「4.参照している変数の値を保持している」ではないでしょうか。

何故変数の値を保持できるのか

closure関数は10行目で実行されています。 ローカル変数counterはclosure関数の終了とともに破棄されるはずです。 ところが、サンプルではclosure関数が代入された、func1・func2が実行された結果を見ても判るとおり、 ローカル変数counterの値は保持されています。
これは Activation Object によるものでした。10行目では次のようなことが行われています。

1. func1の宣言でグローバルオブジェクトにプロパティfunc1が定義された 2. closure関数実行でclosure関数のActivationオブジェクトが自動生成される 3. closure関数のActivationオブジェクトにプロパティcounterが定義される 4. closure関数の戻り値である匿名関数の実行で匿名関数のActivationオブジェクトが生成される 5. スコープチェーンが形成された 匿名関数のオブジェクト→closure関数のオブジェクト→グローバルオブジェクト
通常はclosure関数の終了とともにローカル変数は破棄されます。 ところがfunc1に代入された匿名関数がclosure関数のActivationオブジェクトのプロパティcounterを参照しているため破棄されずに残ることになります。
同じことが11行目でも行われ、func1、func2でそれぞれ別のオブジェクト・スコープチェーンを生成しているため、 自身のスコープチェーンの内のcounterの値を返すことになります。

使いどころ

データの保持の仕組みは解りましたが、どのような使い方をするのがもっとも効果的なのでしょうか?
データ保持の仕組みは他にもいろいろありますし、クロージャはメモリリークの問題があるとの記事もたくさん見ました。
自分ではどうにも思いつかず、「クロージャ メリット」「クロージャ 使いどころ」とググッてみましたが、 これといったものは見つけられませんでした。残念。