クロージャ

JavaC#などをずっとしていた方にとって JavaScript でいちばん新鮮な驚きを体験できるのはたぶんこのクロージャだと思います。

で、クロージャっていったい何なの?って言うのは私もまだうまく説明できないのですが、

コードブロックとスコープの組み合わせ

だと理解しています。

なによりもコードを見てください。
以下のコードではHTMLの一部分だけですがボタンがクリックされるたびに値をインクリメントして画面に表示しています。

<script type="text/javascript">
    window.addEventListener("load",function(e){	
        var button = document.getElementById("clickbutton");
        button.addEventListener("click",clickcounter());
    });
    function clickcounter(){
        var counter = 0;
        return function(){
            document.getElementById("number").innerHTML = counter++;
        }
    }
</script>
<body>
    <input type="button" id="clickbutton"  value="クリック!!" />
    <span id="number"></span>

処理の流れとしては

  1. window.onload イベントを登録して呼ばれる。
  2. clickbutton の onclick イベントで clickcounter ファンクションを呼んで戻り値をセット

としています。
ポイントとなるのは clickbutton の onclick イベントの登録時の clickcounter ファンクションを呼んで戻り値をセット という一文です。
通常なら clickcounter ファンクション自体を登録しますが、そうではなくその戻り値を登録しています。その戻り値とは無名関数で記述されている

return function(){
    document.getElementById("number").innerHTML = counter++;
}

の部分になります。この無名関数の中では counter 変数の値をインクリメントして span タグの中にその値を記述しているのですが、 counter 変数自体は無名関数内で宣言されていません。clickcounter ファンクションの中で宣言されています。
この値は clickcounter ファンクションの中で宣言されているため、その生存期間は clickcounter メソッドが終了するまでになります。しかし clickcounter メソッドは内部の無名関数が clickbutton のイベントメソッドに紐付けられて参照され続けているので、生き続けます。clickcounter メソッドが行き続けるということは counter 変数の値も生き続けるということなので、クリックされるたびに同一のインスタンスが参照されインクリメントされていくわけです。


えー、だいぶ分かりづらい説明になってしまってますが一度使ってみてください。病み付きになるのは間違い無しです。


「そんなん、使う必要あれへんやん。わてらみたいにイントラでしかつかわへん業務アプリケーションやし、凝った動きもせぇへんから JavaScript なんて HTML タグに onclick = 'buttonclick();' って書いてごにょごにょまわしたらしまいや」っておっしゃるそこのあなた。そんなことはありません!めっちゃ使えます。次回、イントラで業務アプリケーションで凝った動きをしなくっても、こうすれば今ままでわざわざ タグに書いていたのが嘘のようと思えるサンプルをご紹介します。