JavaScript で Closure(クロージャ)を使ってみよう

phiary に引っ越しました. 毎日プログラミングやWebに関する情報を発信しています! RSS 登録してたまに覗いたり, tweet やハテブして拡散してもらえると幸いです.

Pocket

今回は, JavaScript を使う上で重要な概念のひとつ, Closure(クロージャ)についてのサンプルを作りました.

Closure(クロージャ)とは

wiki によると

クロージャ(クロージャー、closure、閉包)はプログラミング言語における関数の一種。引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決することを特徴とする

ということらしいです. はい, 意味がわかりませんw

ざっくり説明すると, 関数を定義した際のローカル変数の値を関数に紐付けて参照可能にする仕組みのことです. これによって, 状態(変数)を保持した関数を生成することが可能となります.

感覚としては

関数 < クロージャ < オブジェクト
[/code]

って感じかな?

このへんは使ってみて感覚で理解するのが一番だと思います. クロージャを活用したサンプルが下記にあるので眺めてみてください.

Sample and Download

今回制作したサンプルはこちらです.

ファイルはこちらからダウンロードできます.

最初は i が関数に関連付けられていないので, 同じ値が出力されていますが, それ以降の with や 無名関数を使って closure を使っている場所では 実行時の i が 関数に紐付けされているので 0, 1, 2... と出力されているのが わかるかと思います.

Code

サンプルのスクリプト部分です.

window.onload = function() {
    var funcs = [];
    
    // 
    // 普通に関数を作る
    // 
    log("普通に関数を作る");
    for (var i=0; i<5; ++i) {
        funcs[i] = function() { return (i); };
    }
    // 同じ i を参照してしまっているのでどれも同じ値が出力される
    log(funcs[0]());
    log(funcs[1]());
    log(funcs[2]());
    log(funcs[3]());
    log(funcs[4]());
    
    
    
    // 
    // with でクロージャを作る
    // 
    log("with でクロージャ");
    for (var i=0; i<5; ++i) {
        with({num:i}) {
            funcs[i] = function() { return (num); };
        }
    }
    log(funcs[0]());
    log(funcs[1]());
    log(funcs[2]());
    log(funcs[3]());
    log(funcs[4]());
    
    
    // 
    // 無名関数
    // 
    log("無名関数でクロージャ");
    for (var i=0; i<5; ++i) {
        funcs[i] = (function(i){
            return function() { return (i); };
        })(i);
    }
    log(funcs[0]());
    log(funcs[1]());
    log(funcs[2]());
    log(funcs[3]());
    log(funcs[4]());
    
    
    /*
    // let でクロージャを作る
    log("let でクロージャ");
    for (var i=0; i<5; ++i) {
        let (n = i) {
            funcs[i] = function() { return (n); };
        }
    }
    log(funcs[0]());
    log(funcs[1]());
    log(funcs[2]());
    log(funcs[3]());
    log(funcs[4]());
    */
    
    // 
    // with を使ってクリックイベントを登録
    // 
    var boxList = document.getElementsByClassName("box");
    var colorList = ["red", "yellow", "green", "blue", "purple"];
    for (var i=0; i<5; ++i) {
        // クロージャ
        with({num:i}) {
            boxList[i].onclick = function() {
                this.style.backgroundColor = colorList[num];
            };
        }
    }
};

// ログ出力
var log = function(str) {
    var eConsole = document.getElementById("console");
    eConsole.innerHTML += str;
    eConsole.innerHTML += '\n';
};
[/code]

Tips

with でクロージャ

with に渡されたオブジェクトのプロパティを with 内で定義した関数内で参照することでクロージャを実現しています.

with に渡されたオブジェクトのプロパティは with 内に縛られるためこういったことが可能になります.

無名関数によるクロージャ

無名関数内で宣言された変数もまたスコープが無名関数内のみにとどまるので, with 同様引数として渡された値を 無名関数内で定義した関数内で参照することでクロージャを実現しています.

Reference

サッカーってやっぱ面白いなぁ~. バルサもサントスも最高!!

TRACK BACK URL

POST COMMENT

メールアドレスが公開されることはありません。