JavaScript クロージャーの徹底解説 (Closure)

高洛峰
リリース: 2016-10-15 17:45:14
オリジナル
881 人が閲覧しました

クロージャ - どこでも

フロントエンド プログラミングでは、意図的または非意図的に、直接的または間接的にクロージャを使用することがよくあります。クロージャにより、データ転送をより柔軟にすることができます (一部のクリック イベントの処理など)

!function() {      
  var localData = "localData here";    
     document.addEventListener('click',    //处理点击事件时用到了外部局部变量,比如这里的localData       
        function(){              
           console.log(localData); 
    }); 
}();
ログイン後にコピー

別の例は次のとおりです: (とてもフレンドリーですね~~)

!function() {      
  var localData = "localData here";      
  var url = "http://www.baidu.com/";      
  $.ajax({ 
     url : url,          
     success : function() {              
        // do sth...              
        console.log(localData); 
        } 
    }); 
}();
ログイン後にコピー

別の例を見てみましょう~~この状況は私たちが通常行うものですcall Closure

function outer() {   
  var localVal = 30;    
  return function(){      
    return localVal;    
  } 
} 
var func = outer();  
func(); // 30
ログイン後にコピー

この例では、outer() が呼び出され、無名関数 function() が返されます。この無名関数では、outer() の呼び出しが完了した後に、outer() のローカル変数 localVal にアクセスできます。 func() が再度呼び出されても、outer() のローカル変数 localVal にアクセスできます

クロージャの概念

通常の関数とは異なり、クロージャにより、関数は直接の字句の外で呼び出された場合でも非ローカル変数にアクセスできます範囲。 --Wikipedia

クロージャは、他の関数の内部変数を読み取ることができる関数です。 --Ruan Yifeng

JavaScript 言語では、関数内のサブ関数のみがローカル変数を読み取ることができるため、クロージャーは単に「関数内で定義された関数」として理解できます。

つまり、本質的に、クロージャは関数の内部と関数の外部をつなぐ橋です

クロージャの使い方

この部分はこのブログ投稿からの転載です

クロージャはさまざまな場所で使用できます。その最大の用途は 2 つあり、1 つは前述したように関数内の変数を読み取ること、もう 1 つはこれらの変数の値をメモリに保持することです。

function f1(){
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000
ログイン後にコピー

このコードでは、result は実際にはクロージャ f2 関数です。これは 2 回実行され、1 回目の値は 999、2 回目の値は 1000 でした。これは、関数 f1 のローカル変数 n が常にメモリに格納され、f1 が呼び出された後に自動的にクリアされないことを証明します。

なぜこれが起こっているのですか?その理由は、f1 が f2 の親関数であり、f2 がグローバル変数に割り当てられているため、f2 は常にメモリ内に存在し、f2 の存在は f1 に依存するため、f1 は常にメモリ内にあり、削除されないためです。呼び出しが完了すると、ガベージ コレクション メカニズム (ガベージ コレクション) によってリサイクルされます。

このコードでもう 1 つ注目すべき点は、「nAdd=function(){n+=1}」という行です。まず、var キーワードが nAdd の前に使用されていないため、nAdd はローカル変数ではなくグローバル変数です。 。次に、nAdd の値は匿名関数であり、匿名関数自体もクロージャであるため、nAdd は関数の外部で関数内のローカル変数を操作できるセッターと同等です。

クロージャーのカプセル化

(function() {   
   var _userId = 23492;   
   var _typeId = 'item';    
   var export = {}; 
     
   function converter(userId) {          
     return +userId; 
   } 
    export.getUserId = function() {         
       return converter(_userId);     
   } 
   export.getTypeId = function() {          
      return _typeId; 
   }         
   window.export = export;   //通过此方式输出
}());
 
  export.getUserId(); // 23492 
  export.getTypeId();  // item 
  export._userId;    // undefined  
  export._typeId;    // undefined       
  export.converter; // undefined
ログイン後にコピー

クロージャーの特性を使用すると、いくつかの複雑な関数ロジックをカプセル化できます。この例では、export のメソッド (getUserId、getTypeId) を呼び出すと関数内のプライベート変数に間接的にアクセスしますが、export は直接呼び出します。 _userId は _userId を取得できません。これは Node でよく使用される機能でもあります~

よくある間違い: ループ クロージャ

次のケースでは、値 aaa、bbb、ccc を持つ 3 つの div を追加します。私たちが実現したいのは、aaa をクリックして、出力 1、bbb をクリック 出力 2、ccc をクリックして出力 3

document.body.innerHTML = "<div id=div1>aaa</div>" + "<div id=div2>bbb</div><div id=div3>ccc</div>";  
for (var i = 1; i < 4; i++) {      
  document.getElementById(&#39;div&#39; + i).         
    addEventListener(&#39;click&#39;, function() {         
    alert(i); // all are 4! 
    });  
}
ログイン後にコピー

JavaScript クロージャーの徹底解説 (Closure)

その結果、aaa、bbb、または ccc をクリックするとすべてalert(4)~~

問題は、i の値がすでに初期化が完了したら 4 を実行します

目的を達成するには、aaa をクリックして 1 を出力し、bbb をクリックして出力 2 を、ccc をクリックして 3 を出力します。各ループで、クロージャー手法を使用して、匿名でラップする必要があります。このようにすると、alert(i) の値は毎回クロージャ環境の i から取得され、各ループでの i の代入から取得され、1、2 が出力されます。 、 3

document.body.innerHTML = "<div id=div1>aaa</div>" + "<div id=div2>bbb</div>" + "<div id=div3>ccc</div>";  
for (var i = 1; i < 4; i++) {
  !function(i){ //②再用这个参数i,到getElementById()中引用     
    document.getElementById(&#39;div&#39; + i).       
      addEventListener(&#39;click&#39;, function() {         
      alert(i); // 1,2,3
     });  
  }(i);  //①把遍历的1,2,3的值传到匿名函数里面
}
ログイン後にコピー

JavaScript クロージャーの徹底解説 (Closure)

考える質問

如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。(来自阮老师)这题目总结得真秒~~

代码片段一。

var name = "The Window";
var object = {
  name : "My Object",
  getNameFunc : function(){
    return function(){
      return this.name;
    };
  }
};
alert(object.getNameFunc()());
ログイン後にコピー

代码片段二。

var name = "The Window";
var object = {
  name : "My Object",
  getNameFunc : function(){
    var that = this;
    return function(){
      return that.name;
    };
  }
};
alert(object.getNameFunc()());
ログイン後にコピー


ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート