実例を通してJavaScriptを勉強します.

4907 ワード

を選択します.
前のブログでは、カウンタを実現することによって、クローズドをどのように使うかを知りました.このブログはコードの例を提供して、クローズドを理解するのに役立ちます.
JavaScript Cloures for Dummies
Funebug
可読性を保証するために、本文は直訳ではなく意訳を採用する.また、この著作権は元の作者に帰属し、翻訳は学習にのみ使用されます.
カバンを閉じるのは不思議ではないです
実は、クローズドの肝心な概念を理解しさえすれば、すべてはとても簡単です.JavaScriptの開発者として、以下のコードが理解できるはずです.
Example 1
function sayHello(name) 
{

  var text = 'Hello ' + name;

  var sayAlert = function() { console.log(text); }

  sayAlert();
}

sayHello("Bob") //   "Hello Bob"
sayHello()関数でsayAlert関数を定義して呼び出しました.sayAlert()は内層関数として、外層関数sayHello()のtext変数にアクセスできます.これを理解すれば、このブログを読み続けることができます.
パッケージの例
二つの文はまとめて閉じます.
  • クローズドは関数の局所変数であり、これらの変数は関数returnの後でも
  • にアクセスできます.
  • クローズドは関数のメモリスタックであり、このメモリスタックは関数returnの後に回収されていません.
    Example 2
    function sayHello2(name) 
    {
      var text = 'Hello ' + name; //     
    
      var sayAlert = function() { console.log(text); }
    
      return sayAlert;
    }
    
    var say2 = sayHello2("Jane");
    say2(); //   "Hello Jane"
    sayHello 2()関数を呼び出してsayAlertを返します.これは参照変数で、関数を指します.ほとんどのJavaScriptプログラマは参照変数とは何かを理解することができると信じていますが、CプログラマはsayAlertおよびsay 2を指向関数の指針として理解することができます.
    CポインタとJavaScript参照変数は実質的に区別されていません.JavaScriptでは、関数に対する参照変数は関数自体だけでなく、暗黙的にクローズドを指していることをこのように理解しても良い.
    コードの中の匿名関数function(){alert(text)}は別の関数、すなわちsayHello 2()で定義されています.JavaScriptでは、関数に関数を定義すると、クローズドが作成されます.
    C言語および他のほとんどの言語について:関数return後、その局所変数はメモリのスタックが破壊されるため、アクセスできなくなります.
    JavaScriptについて、関数を定義すると、外層関数returnの後、その局所変数はまだアクセスできます.コードの中ですでにこの点を証明しました.sayHello 2()関数returnの後、say 2()関数を呼び出して、text変数を成功的に印刷しました.そして、text変数はsayHello 2()関数の局所変数です.
    その他の例
    定義された観点からのみ閉包を理解するのは明らかに難しい.しかし、コード例によって、閉じられたパケットが理解されると、多くのことが簡単である.したがって、各例をよく理解して、それらがどのように実行されているかを確認することを強く勧めます.これにより、多くの奇妙なバグが回避されます.
    Example 3
    Example 3では、say 667()関数return後もnum変数はメモリに保存されます.また、sayNumba関数のnum変数はコピーではなく引用であるため、666ではなく667を出力しています.
    function say667() {
    
      var num = 666; // say667()  return ,num           
    
      var sayAlert = function() { console.log(num); }
    
      num++;
    
      return sayAlert;
    
    }
    
    var sayNumba = say667();
    
    sayNumba(); //   667
    Example 4
    Example 4では、3つの大域関数gAlertNumber、gIncrease Number、gSetNumberは、同じsetupSomeGlobals()呼び出しで宣言されているので、同一のクローズパケットを指しています.それらが指すクローズドは、num変数を含むsetupSomeGlobals関数の局所変数です.つまり、それらは同じnum変数で動作します.
    function setupSomeGlobals() {
    
      var num = 666;
    
      gAlertNumber = function() { console.log(num); }
    
      gIncreaseNumber = function() { num++; }
    
      gSetNumber = function(x) { num = x; }
    
    }
    
    setupSomeGlobals();
    gAlertNumber(); //   666
    
    gIncreaseNumber();
    gAlertNumber(); //   667
    
    gSetNumber(5);
    gAlertNumber(); //   5
    Example 5
    Example 5のコードは比較的難しいです.多くの人が同じミスをします.その実行結果は直感に反しているかもしれません.
    function buildList(list) 
    {
      var result = [];
    
      for (var i = 0; i < list.length; i++) 
      {
        var item = 'item' + list[i];
        result.push( function() { console.log(item + ' ' + list[i])} );
      }
    
      return result;
    }
    
    var fnlist = buildList([1,2,3]);
    
    for (var j = 0; j < fnlist.length; j++) 
    {
      fnlist[j](); //     3 "item3 undefined"
    }
    result.push(function(){alert}は、匿名関数function(){alert}に向けられた参照変数を配列に加え、その効果は以下の通りである.
    pointer = function() {alert(item + ' ' + list[i])};
    result.push(pointer);
    コード実行後、連続して3つの「item 3 undefined」を出力しましたが、直感とは明らかに違います.
    buildList()関数を呼び出した後、配列には3つの関数があり、この3つの関数は同じクローズドを指しています.一方、クローズド中のitem変数値は「item 3」、i変数値は3です.3つの関数が同じクローズドパケットを指すことを理解すれば、出力結果は分かりやすくなります.
    Example 6
    Example 6では、alice変数はsayAlert関数の後で定義されていますが、コードの実行には影響がありません.戻り関数sayAlice 2が指すクローズドはsayAlice関数のすべての局所変数を含みます.これはもちろんalice変数を含んでいますので、通常は「Hello Alice」を印刷できます.
    function sayAlice() 
    {
      var sayAlert = function() { console.log(alice); }
    
      var alice = 'Hello Alice';
    
      return sayAlert;
    }
    
    var sayAlice2 = sayAlice();
    
    sayAlice2(); //   "Hello Alice"
    Example 7
    Example 7により、newClose()を呼び出すたびに独立したクローズドが作成され、それらの局所変数numとrefの値が異なることが分かります.
    function newClosure(someNum, someRef) 
    {
      var anArray = [1,2,3];
      var num = someNum;
      var ref = someRef;
    
      return function(x) 
      {
          num += x;
    
          anArray.push(num);
    
          console.log('num: ' + num + "; " + 'anArray ' + anArray.toString() + "; " + 'ref.someVar ' + ref.someVar);
        }
    }
    
    closure1 = newClosure(40, {someVar: "closure 1"}); 
    closure2 = newClosure(1000, {someVar: "closure 2"}); 
    
    closure1(5); //   "num: 45; anArray 1,2,3,45; ref.someVar closure 1"
    closure2(-10); //   "num: 990; anArray 1,2,3,990; ref.someVar closure 2"
    締め括りをつける
    厳密には、クローズドの説明は正確ではありませんが、クローズドを簡単に局所変数としてみて、より簡単に理解できます.
    参照リンク
  • Private Members in JavaScript
  • メモリLeakage in Internet Explorer
  • 著作権声明:転載する時、作者のFunebugと本文の住所を明記してください.https://blog.fundebug.com/201...