JavaSctiptにおけるスコープチェーンとクロージャ

投稿者: | 2016-05-07

今回の記事はスコープチェーンとクロージャについてです。JavaScriptの言語仕様の中では特にわかりにくい部類ではないでしょうか。このあたりの説明は開眼!JavaScriptがとてもわかりやすかったです。

スコープチェーン

過去の記事似て変数のスコープについて説明した通り、JavaScriptはブロックスコープは実装されておらず、関数スコープが実装されています。ですので関数内で宣言された変数(var文で定義した変数)は、その関数内と関数内で定義されている入れ子の関数での使用に限定されます。したがって、インタプリタは変数を検索する際、現在の関数内部⇒親関数の内部⇒その親関数の内部⇒…⇒グローバルオブジェクトの順に検索していきます。このつながりをスコープチェーンと呼びます。なお、各スコープで同名の変数が定義されていたとしても、JavaScriptはスコープチェーン上で最初に見つかった変数が適用されます。

スコープチェーンはいつ決められる?

スコープチェーンは関数定義時に決められます。関数オブジェクトの生成時ではありません。したがって関数オブジェクトをどのような変数に代入しても、どのような関数の戻り値や引数にしたとしても、関数定義時のスコープチェーンが維持されます。

function chainTest() {
    var hoge = "hoge prop";
    var childFunc = function() {
        return hoge;            // hogeは親関数のスコープ上の変数なのでアクセス可能
    }
    return childFunc;           // 親関数が入れ子関数を戻り値として返す
}

var execFunc = chainTest();     // 変数に入れ子関数が代入される
// 入れ子関数を実行する
// スコープチェーンは関数定義時に生成されているので、スコープチェーンを辿ってhogeにアクセスする
console.log(execFunc());    // hogeの値が出力される

スコープチェーンが関数定義時に生成される例として、以下のコードも参考になります。

var prop = 100;

var childFunc = function () {
    console.log(prop);
};

var parentFunc = function (func) {
    var prop = 1;
    func();
};

parentFunc(childFunc);  // 100が出力される

childFuncにてコンソールに出力する変数propはchildFunスコープ外なのでスコープチェーンを辿って検索されます。parentFuncは関数オブジェクトを引数に受け取る関数で、parentFuncのスコープ内で変数propを宣言しています。parentFuncの引数にchildFuncを渡して実行すると、グローバルスコープで宣言した値が出力されます。このことからスコープチェーンは関数の実行時ではなく、関数定義時に生成され、そのチェーンが保持されることがわかります。

クロージャ

クロージャは「スコープチェーンに存在する変数への参照を保持している関数」です。スコープチェーンの項でも説明した通り、JavaScriptにおける関数は必ずスコープチェーンを持っているのですべからくクロージャであると言えます。さて、このクロージャというもの、いったいどのようなシーンで利用できるのでしょうか。一例として、ローカル変数を特定のメソッド(アクセッサ)にアクセスを限定させるといったことが可能です。

var privateAccess = (function() {
    var n = 0;
    return {        // 2つのクロージャをオブジェクトリテラル形式で返す
        getProp: function () {
            return n;
        },
        setProp : function (value) {
            n = value;
        }
    }
})();

console.log(privateAccess.getProp());
privateAccess.setProp(100);
console.log(privateAccess.getProp());

まとめ

スコープチェーンとクロージャについてまとめました。クロージャは実用のコードでどのように扱われているのかが気になるところです。