今作ろうとしているhtmlワンページミニゲームの課題がクロージャで解決できそうな気がするんだけど、何度見てもややこしいので基本のおさらい。
なお既にあるミニゲームは以下です。
gitHub - games
- マインスイーパ
- ライフゲーム
(ライフゲームが何なのかについてはWikipedia参照)
サンプルと動きを見た方が早いと思います
function outerFunc() {
// クローズされる変数
var x = 1;
// 無名関数
return function() {
alert (x);
x+=1;
}
}
function main() {
var f = outerFunc();
f();
f();
f();
}
mainを呼んだ場合の実行結果(アラートが三回、一回毎に以下が出る)
1
2
3
どういうことなの
- mainでは、outerFunc関数内で定義された無名関数が変数fに代入され、f()で呼び出される。 ※JavaScriptでは関数もオブジェクトなので変数に代入できます
- 無名関数はxをクローズ(閉じ込め)している。xは本来outerFunc関数の外(ここではmain関数)からは参照できないが、無名関数を呼び出すことでその中のx呼び出し(alert)をキックできる。ここまではいい。
- 問題なのは無名関数の中でやってるxへのインクリメントが、再呼び出しされてもリセットされていないこと。
- これがクロージャのキモ。変数の解決を、実行時ではなく定義時のコンテクストで静的に行う。
- mainというコンテクストで毎回outerFuncが実行されるわけではなく、静的な変数xが毎回無名関数に呼び出されている。
- 何を言ってるかわからねーと思うが私も正直直感的には理解できない。気持ち悪い
使いどころって?
一回しか押させたくないボタンのプッシュカウントなど、ページがリロードされない限りは保っておきたい変数をいじるのにはいいようです。
グローバル変数を定義するのとどう違うのかは…ページロード時ではなく呼び出し時(つまり任意のタイミング)で初期化できるってところ…かな…?
こんなこともできるよ
上記でいうouterFunc関数や、その中の無名関数に引数を渡すこともできる。
function outerFunc(foo) {
return function(bar) = {alert(foo + (bar*2));};
}
こいつの呼び出し方ごとの結果は以下のような感じになる。
var f = outerFunc(3);
alert(f(5)); // 13と出る(fooが3、barが5)
var f2 = outerFunc(4);
alert(f(7)); // 18と出る
この無名関数の中でまたfooをいじって再呼び出ししたらどうなるのか(予測通り静的変数として扱われるのか)は後ほど確認して更新します。
やー、ややこしい。