javascriptの閉鎖を深く理解する(一)


クローズド(closure)はJavascript言語の一つの難点であり、その特色でもあり、多くの高級アプリケーションはクローズドによって実現されます.
一、クローズドとは何ですか?公式」の説明は、クローズドは多くの変数とこれらの変数を結びつける環境を持つ表現であり、これらの変数もこの式の一部であるということです.
この言葉を直接読む人は少ないと思います.彼の説明はあまりにも学術的なものですから.実はこの言葉は分かりやすく言えば、JavaScriptの中のすべてのfunctionは一つのクローズドです.しかし、一般的には、ネストされたfunctionによって生じたクローズドがより強く、ほとんどの場合、私たちがいわゆる「クローズド」と呼んでいます.
クローズドを理解するには、まずJavascriptの特殊な変数のスコープを理解しなければならない.
二、変数のスコープ
変数のスコープは、大域変数と局所変数の2つにすぎません.
Javascript言語の特殊な点は、関数内部で直接大域変数を読み取ることができることです.
var n=999;

function f1(){
    alert(n);
}

f1(); // 999
一方、関数の外部では当然、関数内の局所変数を読み取ることができません.
function f1(){
  var n=999;
}

alert(n); // error
関数内部で変数を宣言する場合は、必ずvarコマンドを使用してください.使わないなら、実際にグローバル変数を宣言しました.
function f1(){
   n=999;
}

f1();

alert(n); // 999
三、外部からローカル変数を読み取るにはどうすればいいですか?
様々な理由から関数内の局所変数を得る必要があります.しかし、前にも話しましたが、普通の状況ではできません.変通方法でしか実現できません.
それは関数の内部で、もう一つの関数を定義することです.
function f1(){
    n=999;
    function f2(){
      alert(n); // 999
    }
}
上のコードでは、関数f 2が関数f 1の内部に含まれており、f 1の内部のすべての局所変数は、f 2に対して可視である.しかし、逆にだめです.f 2内部の局部変数は、f 1に対しては見えません.これはJavascript言語特有の「連鎖作用領域」構造であり、
サブオブジェクトは、すべての親オブジェクトの変数を1段階ずつ上に探します.したがって、親オブジェクトのすべての変数は、子オブジェクトに対しては見えますが、逆は成立しません.
f 2は、f 1の局所変数を読み取ることができるので、f 2を戻り値とすると、f 1の外部で内部変数を読み出すことができるのではないでしょうか?
function f1(){

    n=999;

    function f2(){
      alert(n);
    }

    return f2;

}

var result=f1();

result(); // 999
上のコードのf 2関数は、クローズドです.
各種の専門文献の「クローズド」の定義はとても抽象的で、分かりにくいです.私の理解では、クローズドとは他の関数の内部変数を読み取ることができる関数です.
Javascript言語では、関数内部のサブ関数だけが局所変数を読み取ることができるので、クローズドを単に「関数の内部に定義された関数」と理解することができます.
したがって、本質的には、クローズドとは、関数の内部と関数の外部をつなぐ橋のことである.
四、クローズドの用途
クローズドは多くのところで使えます.その最大の用途は二つあります.一つは前に述べた関数内部の変数を読み取ることができます.もう一つはこれらの変数の値を常にメモリに保存させます.
この言葉はどうやって理解しますか?下のコードを見てください.
function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){
      alert(n);
    }

    return f2;

}
var result=f1();
result(); // 999
nAdd();
result(); // 1000
このコードの中で、resultは実はクローズドf 2関数です.全部で二回運行しました.一回目の値は999、二回目の値は1000です.これは、関数f 1の局所変数nがメモリに保存されており、f 1呼び出し後に自動的に消去されないことを証明している.
どうしてですか?f 1はf 2の親関数であり、f 2はグローバル変数を与えられ、f 2は常にメモリにあり、f 2の存在はf 1に依存しているため、f 1も常にメモリにあり、呼び出しが終了した後、ゴミ回収メカニズムによって回収されることはない.
このコードのもう一つの注目すべき点は、「nAdd=function(){n+=1]」という行であり、まずnAddの前にvarキーワードが使用されていないため、nAddは局所変数ではなくグローバル変数である.次に、nAddの値は匿名関数であり、これは
匿名関数自体もクローズドなので、nAddはsetterに相当し、関数の外部で関数内部の局所変数を操作することができる.
五、クローズドを使う注意点
1)クローズドは関数の変数がメモリに保存されるため、メモリの消耗が大きいので、クローズドを濫用してはいけません.そうでないと、ウェブページの性能問題が発生し、IEでメモリのリークを引き起こす可能性があります.解決方法は、関数を終了する前に使用しないローカル変数をすべて削除します.
2)親関数の外部で、親関数の内部変数の値を変更します.したがって、親関数を対象として使用する場合は、クローズドをそのパブリックメソッドとして、内部変数をそのプライベート属性として扱わないように注意してください.
親関数の内部変数の値を変更します.
六、思考問題
下記のコードの運行結果を理解していただければ、クローズドの運行メカニズムを理解してもいいと思います.
var name = "The Window";   
  var object = {  
    name : "My Object",  
    getNameFunc : function(){  
      return function(){  
        return this.name;  
     };   
    }   
};  
alert(object.getNameFunc()());  //The Window
七、JavaScriptの閉鎖例
function outerFun()
 {
  var a=0;
  function innerFun()
  {
   a++;
   alert(a);
  }    
 }
innerFun()

//         .innerFun()     outerFun() // ,  outerFun()         .

//    ,     :

function outerFun()
{
 var a=0;
 function innerFun()
 {
  a++;
  alert(a);
 }
 return innerFun;  //    
}
var obj=outerFun();
obj();  //   1
obj();  //   2
var obj2=outerFun();
obj2();  //   1
obj2();  //   2
また何を見に来ましたか?
内部関数がその作用領域を定義する外部で参照されると、その内部関数のクローズドが作成され、内部関数が外部関数にある変数を参照すると、外部関数の呼び出しが完了すると、これらの変数はメモリから解放されません.
もう一つの例を見にきます.
function outerFun()
{
 var a =0;
 alert(a);  
}
var a=4;
outerFun();
alert(a);
結果は0、4.  関数の内部でvarキーワードメンテナンスaを使用しているので、outFun()の内部にあります.
次のコードを見てください.
unction outerFun()
{
 //  var
 a =0;
 alert(a);  
}
var a=4;
outerFun();
alert(a);
結果は
0,0はおかしいです.なぜですか?
作用するドメインチェーンは、経路に沿って変数の値を決定する経路を記述する用語であり、a=0を実行すると、varキーワードが使用されていないので、値付け動作は、作用するドメインチェーンに沿ってvar a=4になる.  を選択し、値を変更します
javascriptに対して閉め切ったらまだよく分かりません.もう一度見てもいいです.
次の文章!