導入
閉鎖とは、別の関数範囲で変数にアクセスする許可を持つ関数です。
JavaScriptで閉鎖を理解するのは困難です。多くの高度なアプリケーションは、それらを実装するために閉鎖に依存しています。まず以下の例を見てみましょう。
function outer(){var i = 100; function inner(){console.log(i); }}上記のコードでは、変数の範囲に従って、関数外側のすべてのローカル変数が関数内側に表示されます。関数内の局所変数は、関数内側の外側では見えないため、関数内の局所変数を関数内側の外側で読み取ることができません。
関数の内側は、内側が戻り値として使用される限り、関数の外側のローカル変数を読み取ることができるため、内部のローカル変数をOUERの直接読み取ります。
function outer(){var i = 100; function inner(){console.log(i); } return inner;} var rs = outer(); rs();この関数には2つの特性があります。
この方法でvar rs = outer()を実行した後、実際のrsは関数の内側を指します。このコードは実際には閉鎖です。つまり、関数の外側の内側の内側の関数が関数の外側の変数によって参照される場合、閉鎖が作成されます。
範囲
簡単に言えば、スコープは、変数と関数のアクセス可能な範囲です。つまり、スコープは変数と関数の可視性とライフサイクルを制御します。 JavaScriptでは、変数の範囲はグローバルでローカルです。
グローバル範囲
var num1 = 1; function fun1(){num2 = 2;}上記の3つのオブジェクトNum1、num2、およびfun1はすべてグローバルスコープです。ここでは、最後に直接割り当てを定義する変数が自動的にグローバルなスコープを持っていると宣言されることに注意する必要があります。
ローカルスコープ
function wrap(){var obj = "私はラップで包まれています。ラップの外側は直接アクセスできません"; function innerfun(){//外側は私にアクセスできません}}スコープチェーン
JavaScriptのすべてはオブジェクトです。これらのオブジェクトには、[[scope]]プロパティがあり、関数によって作成されたスコープにオブジェクトのコレクションが含まれています。このコレクションは、関数のスコープチェーンと呼ばれ、関数によってアクセスできるデータを決定します。
関数add(a、b){return a+b;}関数が作成されると、その[[scope]]プロパティがグローバルスコープを自動的に追加します
var sum = add(3,4);
関数が呼び出されると、実行コンテキストと呼ばれる内部オブジェクトが作成されます。このオブジェクトZは、機能が実行されるときに環境を定義します。また、識別子解像度のための独自のスコープチェーンがあり、そのスコープチェーンは、現在の実行機能の[[scope]]に含まれるオブジェクトとして初期化されます。
関数の実行中、変数に遭遇するたびに、識別子解析プロセスが渡され、データを取得して保存する場所を決定します。このプロセスは、スコープチェーンのヘッドから始まります。つまり、アクティブオブジェクトから同じ名前の識別子を検索します。見つかった場合は、この識別子に対応する変数を使用します。見つからない場合は、スコープチェーン内の次のオブジェクトを検索し続けます。すべてのオブジェクトが検索されている場合(最後のオブジェクトはグローバルオブジェクトです)、識別子は未定義と見なされます。
閉鎖
閉鎖は、単に外部変数にアクセスする関数です。
var quo = function(status){return {getstatus:function(){return status; }}}ステータスはquoで保存され、オブジェクトを返します。このオブジェクトのメソッドgetStatusは、ステータス変数、つまりgetStatus関数に外部変数ステータスにアクセスします。
var newValue = quo( 'string'); // newValue.getStatus()でnewValueが参照した匿名オブジェクトを返します; // quoの内部変数ステータスにアクセスしました
getStatusメソッドが使用できない場合、ステータスはquo( 'sting')後に自動的にリサイクルされます。それはまさに、返された匿名オブジェクトがグローバルオブジェクトによって参照され、匿名オブジェクトがステータスに依存するため、ステータスのリリースを防ぐためです。
例:
//エラースキームvar test = function(nodes){var i; for(i = 0; i <nodes.length; i ++){nodes [i] .onclick = function(e){alert(i); }}}匿名関数は閉鎖を作成し、I ITにアクセスするのは外部テスト関数にあるため、各ノードは実際には同じiを参照します。
//改善ソリューションvar test = function(nodes){var i; for(i = 0; i <nodes.length; i ++){nodes [i] .onclick = function(i){return function(){alert(i); }; }(私); }}各ノードはイベントにバインドされています。このイベントはパラメーターを受け取り、すぐに実行し、iを通過します。値で渡されるため、各ループは現在のiの新しいバックアップを生成します。
閉鎖の役割
function outer(){var i = 100; function inner(){console.log(i ++); } return inner;} var rs = outer(); rs(); // 100rs(); // 101rs(); // 102上記のコードでは、RSは閉鎖内の関数です。 RSは合計で3回、100回、2回目は101、3回目は102でした。これは、関数外側のローカル変数Iがメモリに保持され、呼び出されたときに自動的にクリアされなかったことを示しています。
閉鎖の目的は、外側の実行が完了して返された後、閉鎖により、外側の内部関数の実行が外側の変数に依存するため、閉鎖により外側が占めるメモリをリサイクルしないことです。 (別の説明:外側は内側の親機能であり、内側はグローバル変数に割り当てられ、常に内側がメモリになり、内側の存在は外側に依存します。
閉鎖には、関数内のすべての変数にアクセスする許可があります。
関数が閉鎖を返すと、閉鎖が存在しないまで関数の範囲がメモリに保存されます。
閉鎖と変数
スコープチェーンメカニズムにより、閉鎖は関数に変数を含む最後の値のみを取得できます。次の例を参照してください。
function f(){var rs = []; for(var i = 0; i <10; i ++){rs [i] = function(){return i; }; } return rs;} var fn = f();関数は配列を返します。表面的には、各関数は独自のインデックス値を返す必要があるようです。実際、各関数は10を返します。これは、最初の関数のスコープチェーンに関数fのアクティブオブジェクトが含まれており、同じ変数iを参照しているためです。関数fが戻ると、変数Iの値は10です。この時点で、各関数は変数iの同じ変数オブジェクトを保存します。別の匿名関数を作成することにより、予想どおりに閉鎖を強制することができます。
function f(){var rs = []; for(var i = 0; i <10; i ++){rs [i] = function(num){return function(){return num; }; }(私); } return rs;} var fn = f();このバージョンでは、アレイへのクロージャーを直接割り当てる代わりに、匿名関数を定義し、匿名関数をすぐにアレイに実行した結果を割り当てます。ここで、匿名関数にはパラメーター数があります。各関数を呼び出すと、変数iに渡されます。パラメーターは値で渡されるため、変数Iはパラメーターnumにコピーされます。この匿名関数内では、閉鎖にアクセスするnumが作成されて返されます。このようにして、RSアレイの各関数には独自のnum変数のコピーがあるため、異なる値を返すことができます。
閉鎖中のこのオブジェクト
var name = 'jack'; var o = {name: 'bingdian'、getname:function(){return function(){return this.name; }; }} console.log(o.getname()()()); // jackvar name = 'jack'; var o = {name: 'bingdian'、getname:function(){var self = this; return function(){return self.name; }; }} console.log(o.getname()()()); // bingdianメモリリーク
function assignhandler(){var el = document.getElementById( 'demo'); el.onclick = function(){console.log(el.id); }} assighthandler();上記のコードは、EL Elementイベントハンドラーとして閉鎖を作成し、この閉鎖は円形の参照を作成します。匿名関数が存在する限り、EL参照の数は少なくとも1です。
function assignhandler(){var el = document.getElementById( 'demo'); var id = el.id; el.onclick = function(){console.log(id); } el = null;} assighthandler();可変el nullを設定すると、DOMオブジェクトが逆に逆行し、メモリが正常に消費されることを確認できます。
ブロックレベルの範囲を模倣します
Curly Braces({および})の任意のペアに設定されたステートメントは、ブロックに属し、これで定義されているすべての変数は、ブロックレベルのスコープと呼ばれるコードブロックの外側に見えません。
(function(){//ブロックレベルスコープ})();閉鎖の適用
関数内の変数のセキュリティを保護します。前の例のように、関数内側のみが関数の外側にアクセスできますが、他のチャネルを介してアクセスすることはできないため、iのセキュリティを保護します。
メモリに変数を維持します。前の例のように、閉鎖のために、関数外側のiは常にメモリに存在するため、rs()が実行されるたびに1が追加されます1。