LoginSignup
3
4

More than 5 years have passed since last update.

JavaScript クロージャとは

Posted at

意識しないうちに利用しているクロージャだが人に教えるのはなんか難しい。
人に教えねばならぬ機会に恵まれたため、ここに復習の意味も込めて纏めておこうと思う。

関数を理解することが大事

クロージャを理解するにはまず関数の特性を理解するとこからだ。
というか関数を理解できたらそれはクロージャを理解できたことになると思う。

① スコープは関数定義時に決まる

関数内のスコープはローカルスコープとなりますがそれは関数定義時に決まります。
実行時ではありません。これを静的スコープといいます。
これはJavaScriptの関数が定義時のコンテキストで実行されることも意味します。

var scope = 'global';

function func1() {
    console.log(scope);
}

function func2() {
    var scope = 'local';
    func1();
}

func1(); //global
func2(); //global

func1はグローバルスコープに定義されているのでスコープチェーンによってscopeの値は「global」となる。
func2はローカルスコープ内でfunc1が呼び出されているが、実行コンテキストは定義時のコンテキストになるのでやはり結果は「global」となる。

② 関数は第1級オブジェクトである

第1級オブジェクトとは、通常のオブジェクトの様に、プロパティに定義したり、他の関数の引数として渡したり、戻り値にすることができるという意味です。これはJavaScriptの関数は定義されたコンテキストとは異なるコンテキスト上で実行できるということです。

var test = function () {
        console.log('Hello World!!!');
    },

    test2 = function (fn) {
        fn();
    };

test2(test); //Hello World!!!

testはグローバルに定義されていますが、実行はtest2のローカルスコープ内です。

③ 定義時のコンテキストと異なるコンテキストから呼ばれる

この場合にクロージャとなる。①と②を踏まえて以下のコードを見てみる。

function makeCounter() {
  var count = 0;
  return f;
  function f() {
    return count++;
  } 
}
var a = makeCounter();
console.log(a());  // 0
console.log(a());  // 1
console.log(a());  // 2

まず関数makeCounterfという関数を戻り値として返しています。
これは②の関数は第1級オブジェクトであるという特性に当てはまりますね。
このfという関数はmakeCounterの関数内で定義されているので関数内のスコープを参照することができます。これは①のスコープは関数定義時に決まるでした。(スコープチェーン)
そして、makeCounter関数は変数aに格納されグローバルスコープで実行されていますが、
実行コンテキストは関数宣言時のコンテキストとなるので結果countという変数を参照し続けます。

纏め

  1. スコープは関数定義時に決まる
  2. 関数は第1級オブジェクトである
  3. 定義時のコンテキストと異なるコンテキストから呼ばれる

この3つがクロージャの本質となるので覚えておきましょう。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4