JS言語の理解05閉鎖

定義

コンテキストが作成されたときの機能は、クロージャと呼ばれ、アクセスすることができます

内部関数は外部関数よりも長いライフサイクルを持っています

function closure(name) {
  var status = 1;
  return {
    getName: function() {
      return name;
    },
    getStatus: function() {
      return status++;
    }
  }
}
var a = closure('w3ctech');
alert(a.getName()); // w3ctech
alert(a.getStatus()); // 1
alert(a.getStatus()); // 2

関数のスコープ:

  • 変数およびパラメータは関数の外に見えません
  • 変数は、関数内の任意の場所に定義することができ、機能のどこにでも見ることができます
  • ネストされた関数のパラメータおよび変数は、外部関数のためにアクセスすることができます

クロージャシナリオ:

  • プライベートメンバーを達成
  • 保護名前空間
  • 汚染グローバル変数を避けます
  • 変数は、長期記憶に常駐する必要があります

理解の閉鎖

閉鎖リターンがfuncitonです

関数Bの戻り値関数が、Cは外ので、あなたがBを呼び出すのと同等のAを呼び出すとき、Cは直接変数Aにアクセスされるのではなく、B通じ、C変数Aでの訪問に

閉鎖の二つの目的があります。

  • 外部から取得した関数内のローカル変数
  • ローカル変数のこれらの値は、常にメモリの中に存在してみよう
function f1(){
    var n=999;
    function f2(){
        alert(n);//获得f1的内部变量
    }
    return f2;
}
f1()();//f1()返回值是f2,需要对f2再次引用

定義されたクロージャ:閉鎖(クロージャ)は(すなわち定義された関数内の関数)彼の内部変数の関数を読み取ることができる機能である、上記の例では、閉鎖F2は、F2はF1内部戻り値として出力する必要があります。本質的に、クロージャは、内部および外部のブリッジ接続機能の関数です。

F1()()グローバル変数の等価を参照ので、ここでF2は、メモリではなく、通話の終了時に常に従ってガベージコレクション機構をグローバル変数内に存在し、そして、f1とf2 f1の存在に依存(ガベージコレクション)を回収。

クロージャを使用することに留意すべきで:前記メモリ内に存在する変数は、大量のメモリ消費量。

質問

var name = "The Window";
var object = {
  name: "My Object",
  getNameFunc: function() {
    return function() {
      return this.name;
    };
  }
};
alert(object.getNameFunc()()); //结果 The Window

以来、this常に呼び出し元への参照を発現し、object.getNameFunc()戻り値はobject、この関数は、匿名の呼び出し元である内部オブジェクト匿名関数windowので、thisポイントはwindow、最後の文は、印刷と同等でありwindow.name、結果は'The Window'

なぜ返された匿名関数は、その範囲が含まれていませthisオブジェクトを?

各関数は、自動的に呼び出されたときに二つの特別な変数を取得し、しますthisarguments二つの変数の内部検索機能、そのアクティブなオブジェクトまで検索しますので、直接、二つの変数の外部関数にアクセスすることはできません範囲外であるがthis、変数の閉鎖に格納されているオブジェクトが訪れ従事することができ、あなたは、オブジェクトへのアクセスの閉鎖を行うことができます。- "JavaScriptの高度なプログラミング" P182

var name = "The Window";
var object = {
  name: "My Object",
  getNameFunc: function() {
    var that = this;
    return function() {
      return that.name;
    };
  }
};
alert(object.getNameFunc()()); //结果My Object

これは、オブジェクト内の値であり、その結果は私のオブジェクトであること

割り当て周期の例

導入

以下の例で、意図が異なるクリック李ある、対応するインデックスプリントアウトが、結果李がクリックされるに関係なく、結果は3であります

<body>
<p title="选择你最喜欢的水果?">你最喜欢的水果是?</p>
<ul>
    <li id="li1" title="苹果">苹果</li>
    <li title="橘子">橘子</li>
    <li title="菠萝">菠萝</li>
</ul>
<script>
  var li = document.getElementsByTagName('li');
  
  for(var i= 0; i<li.length; i++){
    li[i].onclick = function(){
      alert(i)
    }
  }
</script>

JavaScriptのイベントハンドリング機構

二段階発行コールで得られた結果:一般的に、操作が分割されます。即時の結果のため発行した呼び出しが同期されます。電話をかけますが、すぐに結果を得ることができなかった、それは望ましい結果が非同期で取得するために追加の操作が必要です。結果が返されるまでの呼び出しの後、同期待ちです。呼び出しは非同期です後は、直接、最終的な結果を得るための手段の一連の結果を得ることができない(呼び出した後、中間結果を取得する時間が他のタスクに関与することができます)

JavaScript言語の大きな特徴は、シングルスレッドで、ユーザーのアクションイベントは、onclickのイベントとして非同期呼び出し、onlickイベントが定義されている場合、それは、場合の動作対応するオブジェクトの動作を監視、API対応のブラウザを起動]をクリックしますです後、ブラウザがこのイベントには、タスクキューに対応するコールバック関数です。

エンジンは、すべての文とDOMを(コードのスタックが完了された後には、ある)解決が終了したら、メインスレッドは、コールバック関数に対応し、それらのイベントの実装が続くタスクキューを、読み取ることができます。

スタックコード(同期タスク)は、常に「タスクキュー」の前に行って(非同期タスク)をお読みください。

原因分析

生成されます。このための2つの理由があります。

  1. スコープ、JSブロックスコープはグローバルスコープの機能と範囲だけでなく、
  2. ハンドリング機構JSイベント

次のように上記プロセスは、ループに対して行われます。

  1. ループ用の貫通するたびに、onclickイベントのDOMを呼び出して、イベントは3クリックイベントの合計を追加し、タスクキューに追加されました
  2. 実行のためのすべての文を含むとき、私=、を含む、完成されています。(私= 3 ++の後、私は=最後の文のための2は、内部で実行される)3
  3. イベントループが場に出たとき、ポーリングタスクキューを行いました
  4. 私、地球環境、iの機能で、3はそうです。この時点で、

ソリューション

クロージャはローカルスコープを使用して作成され、私は、各関数に渡され、内部に保存し、2つの特定の方法がありますされています

方法1:私の着信や保存の内部機能を変更します自己実行匿名関数を作成します(実行からキーですので、あなたが待機するキューに配置する必要がありますが、サイクルの実行の過程ではありません)

  /***利用自执行匿名函数创造一个闭包域空间,将i的值储存在函数内部
  for(var i= 0; i<li.length; i++){
    (function(j){
      li[j].onclick = function(){
        alert(j)
      }
    })(i)
  }
  ****/

方法2:クロージャの使用は、新しい匿名の閉鎖空間での結合事象を完了するために、いずれかであり、この場合は新しい匿名関数のリターンに結合事象の関数であり、

for(var i= 0; i<li.length; i++){
    li[i].onclick = (function(j){
      return function(){
        alert(j)
      }
    })(i)
  }

方法3:使用ES6はレベル変数宣言のブロックを聞かせて

  for(let i= 0; i<li.length; i++){
    li[i].onclick = function(){
      alert(i)
    }
  }

その理由は次のとおりです。私が宣言された変数を聞かせて、私はサイクルの現在のラウンドでのみ有効である現在は、私が実際に新しい変数を循環するたびに、最終的な出力は6です。

閉鎖で隠しデータ

多くの場合、関数を作成するために使用されるクロージャは隠されたデータが含まれている(常にではありません)。

var db = (function() {
// 创建一个隐藏的object, 这个object持有一些数据
// 从外部是不能访问这个object的
var data = {};
// 创建一个函数, 这个函数提供一些访问data的数据的方法
return function(key, val) {
    if (val === undefined) { return data[key] } // get
    else { return data[key] = val } // set
    }
// 我们可以调用这个匿名方法
// 返回这个内部函数,它是一个闭包
})();

db('x'); // 返回 undefined
db('x', 1); // 设置data['x']为1
db('x'); // 返回 1
// 我们不可能访问data这个object本身
// 但是我们可以设置它的成员

参照

おすすめ

転載: blog.csdn.net/duola8789/article/details/94740144