【JavaScript】クロージャかんぜんにりかいした

概要

昨日まで全然わからなかったのでメモ。
クロージャは初期化したときの値を外部から変更できないようにした関数みたいに見えますね。

単体で考えていても理解できなかったので、クロージャを使わない場合と使った場合でわけて考えてみました。

クロージャを使わない場合

クロージャを使わない場合のjsをJavaのクラスで無理やり例えるとこんなかんじ、メンバがpublic。

class test1{
  public int number;

  test(){
    this.number = 0:
  }

  public int run(){
    this.number = this.number + 1;
    return this.number;
  }
}

これをjsで書くとオブジェクト内にnumberプロパティとrun関数がある状態みたい。

var test1 = {
  number: 0,
  run: function(){
    this.number = this.number + 1;
    return this.number;
  }
};

console.log(test1.run());// 1
console.log(test1.run());// 2

test1.number = 8; // こうするとnumberに8を代入できてしまう

console.log(test1.run()); // 9
console.log(test1.run()); // 10

オブジェクトままだと上記のように外部からの変更ができてしまうので、勝手に外から変更できないようにするのがクロージャらしい。

クロージャを使った場合

クロージャを使った場合をJavaのクラスで無理やり例えるとこうなる、メンバがprivateな感じ。

class test1{
  private int number;

  test(){
    this.number = 0:
  }

  public int run(){
    this.number = this.number + 1;
    return number;
  }
}

これをjsで書くとこんな感じになる。

var test2 = function(){
  // 「①」でclosure_testに代入したときにここを一回だけ通るのでnumberは0に初期化される
  var number = 0; // ③

  return function(){
    // 「②」の代入後に()で呼び出されるときは、returnされたこの関数が入る
    // なので代入の時にはここは実行されない
    // 内部的に「③」の数値を参照して更新しているので、初期化されずにnumberの数字が増えているみたい
    number = number + 1;
    return number;
  }
};

var closure_test= test2();// ① これがクロージャ

// ②
console.log(closure_test()); // 1
console.log(closure_test()); // 2

closure_test.number = 8; // オブジェクトとは違って、こうしてもnumberに8は代入できない。

console.log(closure_test()); // 3
console.log(closure_test()); // 4

クロージャを使うと、こんな感じで外部からnumberが変更できなくできる。

続けて、関数を実行しない場合のclosure_testの中身をconsole.logで見てみる。

console.log(closure_test);
/*
ƒ (){
    // 「②」の代入後に()で呼び出されるときは、returnされたこの関数が入る
    // なので代入の時にはここは実行されない
    // 内部的に「③」の数値を参照して更新しているので、初期化されずにnumberの数字が増えているみたい
    number = number + 1;
    return number;
  }
*/

closure_testの中身だけ見てみると、returnで返される関数の部分がコメントごと入ってるようだ。
numberはこのclosure_testだけ見るとどこにも定義されていないけれど、スコープ上はローカル変数にあたるnumberの変数を参照しているらしい。
参照してはいるけれど、returnでかえってきた関数にはnumberの初期化処理はないから、numberが初期化されなくて値が保持されたまま(number = number + 1 が実行されて)numberが更新されるみたい。

参考

関数を理解すればクロージャは難しくない!|もっこりJavaScript|ANALOGIC(アナロジック)

オブジェクトとクロージャで書いた場合の比較が書いてあって大変参考になったサイト。

menber変数が使えるのはスコープの範囲が内側から評価されるからみたい? そのあたりを理解するのに大変参考になりました。
javascriptむつかしいのでもっとわかるようになりたいです。

おわり