JS階段シリーズのクローズド

3436 ワード

クローズドとは、他の関数の内部変数を読み取る関数であり、クローズドを単に「関数の内部に定義された関数」として理解することができます.
阮一峰のブログを読んで閉包について説明した後、自分も閉包に対して一定の認識ができました.まず閉包を理解する前に、JavaScriptの特殊な変数の作用領域を理解しなければなりません.変数のスコープには2つの大域変数と局所変数があります.
var n = 999;
function f1(){
  alert(n);
}
f1();//999
以上のコードからJavascript言語の特殊な点が分かります.関数の内部で直接大域変数を読み取ることができます.もちろん、関数の外部では当然、関数内部の局所変数を読み取ることができません.外部から内部の局所変数を読み取るにはどうすればいいですか?関数の内部に関数を定義すると、次のようになります.
function f1(){
  var n = 999;
  function f2(){
      alert(n);//999
}
}
上記のコードでは、関数f2が関数f1に含まれているので、関数f2f1の中の局所変数にアクセスできます.関数f2を戻り値とすると、外部で内部の局所変数を読み取ることができます.コードは以下の通りです.
function f1(){
  var n = 999;
  function f2(){
      alert(n);//999
}
return f2;
}

var result = f1();
result(); //999
実際には上のコードでは、関数f2はクローズドされています.この中では、クローズドされている二つの役割について言及します.最初は関数内部の変数、つまり上記のコードの役割です.二つ目はこれらの変数の値を常にメモリに保持させ、次のコードを見れば第二の役割が理解できるという意味です.
function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){
      alert(n);
    }

    return f2;

  }

  var result=f1();

  result(); // 999

  nAdd();

  result(); // 1000
関数f2は、大域変数resultに値を与えているので、関数f2はメモリに保存され、関数f2の親関数はf1で、f1に依存しているので、f1もメモリに保存され、f1の中の変数もメモリに保存され、回収されない.
この本を読んでいるうちに、二つのパッケージ関連の例プログラムが見つかりました.一つ目は次の通りです.
function createFunctions(){
    var result = new Array();
    for(var i = 0; i < 10; i++) {
        result[i] = function(){
           return i;
       };
   }
   return result;
}
正常に戻った結果は、それぞれの関数が自分のインデックス値を返しますが、最終的な結果は、各関数が10を返します.これは、各関数の作用領域チェーンにcreateFunctions()関数のアクティブオブジェクトが保存されているため、それらが参照するのは同じ変数iであり、createFunctions()関数が戻り、iの値が10になると、各関数は変数iを保存する同じ変数オブジェクトを参照している.次のように、別の匿名関数を作成することにより、強制的に閉じられた動作を予想通りにすることができます.
function createFunctions(){
    var result = new Array();
    for(var i = 0; i < 10; i++) {
        result[i] = function(num){
           return  function(){
                return num;
            }
       }(i);
   }
   return result;
}
二つ目は:
var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      return function(){
        return this.name;
      };

    }

  };

  alert(object.getNameFunc()());
上のコードが返した結果は、「My Object」ではなく「The Window」です.私たちはこれを理解する前に、方法の呼び出しと関数の呼び出しの違いを理解します.最後の言葉を二つの言葉に分解します.
var first = object.getNameFunc();
var result = first();
第1の文で呼び出されたのはobject getNameFunc()の方法であったので、thisのオブジェクトはobjectであったが、第2の文ではfirst()は関数呼出に属し、グローバル環境で呼び出されたのでthis windowになった.
なぜ匿名関数は、スコープ(外部スコープ)を含むthisオブジェクトを取得していないのですか?各関数が呼び出されると、そのオブジェクトは自動的に二つの特殊な変数を取得します.内部関数は、この2つの変数を検索すると、そのアクティブなオブジェクトだけが検索されますので、外部関数の2つの変数に直接アクセスすることはできません.——<>
次のコードを見てください.
var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
                     var that = this;// getNameFunc() this   that   
      return function(){
        return that.name;
      };

    }

  };

  alert(object.getNameFunc()()); //"My Object"
戻ってきた結果は、外部作用領域のthisをクローズドパケットでアクセスできる変数に保存できるので、期待される「My Object」です.