好きなだけかりんとうを食べる人生

フロントエンドとかデザインとかバックエンドとか浅く広く。社会人3年目のうぇぶでぃれくたーです。

クロージャを本能的に理解できない理由を考えたらあっさり解決した話

Javascriptを勉強している方なら誰でもぶち当たる壁、クロージャ
クロージャを理解する=Javascript初心者卒業」とまで言われてたりしていますよね。

サンプルを見たりコードを書いたりしてなんとなくどういうものかは掴めてたのですが、
関数内でreturn使ってもう1コ関数返したらクロージャ」と脳内停止状態で丸暗記している感が否めませんでした。

クロージャのサンプル

function test() {
    var x = 0;
    return function() {
        console.log(x);
        x++;
    };
};

var f = test();
f();    // 0
f();    // 1
f();    // 2

よくあるカウンタですね。
test()が定義されたタイミングで、無名関数はスコープチェーンを辿ってxにアクセスする権利を保持します。
これによって、test()内で宣言されたxを無名関数(子関数。クロージャ。)内から参照し続けることができます。

理解できない原因は何だったのか

自分、ずっと「変数fが呼び出される度にxが0に初期化されるやん!!」って思ってたんです。
スコープチェーンは理解できるけど、呼び出す度に0が代入されたらカウンタもクソもねーだろって。
そこで、ふと以下のコードを実行してみました。

console.log(f);
// function() {
//     console.log(x);
//     x++;
// }

xの初期化(x=0)は変数fにtest()が代入されたタイミングで行われていただけですね。
あとはfが呼び出される度にxが1増加するだけです。 増加したxはスコープチェーンによって保持され、増え続けます。

イメージとしてはこんな感じでしょうか?

f:id:ia_isier:20140406064253p:plain

まとめ

関数が実行されるタイミングreturn文の扱いをきちんと理解していればなんてことはないお話でした。
間違っているようでしたらコメントいただけるとすごくうれしいです。