閉鎖は、JavaScript言語とその機能の難しさです。多くの高度なアプリケーションは、閉鎖に依存して実装しています。私は長い間閉鎖の概念にさらされてきましたが、私は混乱しており、JavaScriptの閉鎖が何であり、それらが何であるかを理解することができませんでした。今日、私はインターネット上のJavaScriptクロージャー(元のリンク)に関する記事を見ました。それは非常によく説明されていました。今、私はJavaScriptの閉鎖が魔法のようなものであり、閉鎖の目的であることを完全に理解しています。私はあなたと共有するためにここにそれらを書きます。 JavaScriptの閉鎖を理解していない友人が閉鎖を読んだ後に理解できることを願っています!次のコンテンツのほとんどは、元のテキストからのものです。いくつかのコードコメント、操作レンダリング、および少しの変更を元のテキストに追加して、簡単に理解しました!
1。変数の範囲
閉鎖を理解するには、最初にJavaScriptの特別な変数範囲を理解する必要があります。
JavaScriptでは、変数の範囲は、グローバル変数とローカル変数の2つのタイプに分割されます。
JavaScriptでは、グローバル変数を関数内で直接読み取ることができます。
var n =; //グローバル変数nfunction f(){alert( "グローバル変数n、n ="+n); //グローバル変数n} f()にアクセスする。 //実行結果:
しかし、逆の方法は不可能です。関数内のローカル変数を関数の外側で読み取ることはできません。
関数f(){var n =; //ローカル変数n} alertを定義する( "関数の外側のローカル変数nにアクセス、n ="+n); //関数の外側のローカル変数nにアクセスすると、エラー:nは定義されていません実行結果:
ここに注意する場所があります。変数を内部的に宣言する場合は、VARコマンドを使用する必要があります。そうでない場合、それは実際には宣言されたグローバル変数です!
関数f(){n =;} f(); alert( "nはf1関数内のvarと宣言されていません。この時点では、nはグローバル変数、 /r /n証明:n ="+n+"、window.n == n is:"+(windo.n == n));実行結果:
2。外部からローカル変数を読む方法は?
さまざまな理由で、関数内でローカル変数を取得する必要がある場合があります。ただし、前述のように、通常の状況では、これは実行できず、回避策によってのみ達成できます。
それは、関数内の別の関数を定義することです。
function f(){var n =; //ローカル変数n内部f関数// f関数f(){// f function、alert(n); //}}上記のコードでは、関数F2が関数F1内に含まれており、F1内のすべての局所変数がF2に表示されます。しかし、逆の方法は不可能です。 F2内のローカル変数は、F1には見えません。これは、JavaScript言語に固有の「チェーンスコープ」構造です。子オブジェクトは、すべての親オブジェクト変数のレベルごとに上向きに見えます。したがって、親オブジェクトのすべての変数が子オブジェクトに表示されます。そうしないと、それは真ではありません。 F2がF1のローカル変数を読み取ることができるため、F2が戻り値として使用される限り、F1以外の内部変数を読むことはできませんか?質問がある人もいるかもしれません。 F2は関数です。F1関数の返品値としてどのように返すことができますか?実際、それは大丈夫です。 JavaScript自体の関数名は変数であるため、関数は通常の変数としても使用できます。つまり、パラメーターを渡すような別の関数に1つの関数を渡すことができるだけでなく、1つの関数を別の関数の戻り値として返すこともできます。
function f(){var n =; //ローカル変数n // f function function f(){alert(n); } return f; // f関数としてf関数をf関数として使用} var result = f(); // fが呼び出された後の戻り値はf関数であり、結果はf関数result()です。 // 999、f2関数を呼び出します実行結果:
3。閉鎖の概念
コードの前のセクションのF2関数は閉鎖です。さまざまな専門文書における「閉鎖」の定義は非常に抽象的です。たとえば、閉鎖定義があります。「JavaScriptの閉鎖は、別の範囲の以前のレベル関数またはスコープから得られる変数であり、これらの変数は、前のレベル関数の実行が完了すると破壊されません。」このような閉鎖の定義を理解することは困難です。私の理解では、閉鎖は他の関数内の変数を読み取ることができる関数であるということです。 JavaScript言語では、関数内のサブファクションのみがローカル変数を読み取ることができるため、閉鎖は「関数内で定義された関数」として簡単に理解できます。したがって、本質的に、閉鎖とは、関数の内側と外側を結ぶブリッジです。
4。閉鎖の目的
閉鎖は多くの場所で使用できます。 2つの最大の用途があります。1つは、関数内の変数を上記のように読み取ることができ、もう1つはこれらの変数の値が常にメモリに保持されることです。
この文を理解する方法は?以下のコードをご覧ください。
関数f(){var n =; // naddは、var。この変数は、f関数nadd = function(){n+=} function f(){alert(n); } furne f; } var result = f(); // resultはf関数result();実行結果:
このコードでは、結果は実際には閉鎖F2関数です。合計で2回実行され、最初の値は999、2番目の値は1000です。これは、関数F1のローカル変数nがメモリに保持され、F1が呼び出された後に自動的にクリアされないことを証明しています。
なぜこれが起こっているのですか?その理由は、F1がF2の親機能であり、F2がグローバル変数に割り当てられ、F2が常にメモリになり、F2の存在はF1に依存するためです。したがって、F1は常にメモリにあり、コールが終了した後、ゴミ収集メカニズムによってリサイクルされません。
このコードのもう1つの注目すべき点は、「nadd = function(){n+= 1}」という行が最初にNADDの前に使用されるため、NADDはローカル変数ではなくグローバル変数であることです。第二に、NADDの値は匿名関数であり、この匿名関数自体も閉鎖であるため、NADDは関数の外側の関数内のローカル変数で動作するセッターと同等です。
5。閉鎖の使用に関するメモ
1)閉鎖は関数のすべての変数をメモリに保存し、メモリ消費量が非常に大きく、閉鎖は乱用できないため、Webページのパフォーマンスの問題を引き起こし、IEでメモリ漏れにつながる可能性があります。解決策は、関数を終了する前に使用されないすべてのローカル変数を削除することです。
2)閉鎖により、親関数の外側の親関数内の変数の値が変更されます。したがって、親関数をオブジェクトとして使用する場合、クロージャーをパブリックメソッドとして使用し、内部変数を私有地として使用します。親関数の内部変数の値をWELで変更しないように注意してください。
6。質問を考えています
次の2つのコードの実行結果を理解できる場合は、閉鎖の実行中のメカニズムを理解することを検討する必要があります。
コードスニペット1:
var name = "The Window"; var object = {name: "my object"、getnamefunc:function(){return function(){return this.name; }; }}; alert(object.getNameFunc()()());実行結果:
コードスニペット2:
var name = "The Window"; var object = {name: "my object"、getnamefunc:function(){var that = this; return function(){return that.name; }; }}; alert(object.getNameFunc()()());実行結果:
次のコメントをコードに追加して、上記の2つのコードスニペットの実行結果を分析します。
コードスニペット1:
分析は次のとおりです。
/*JavaScriptでは、JavaScriptグローバルオブジェクト、グローバル関数、および宣言するグローバル変数は、ウィンドウオブジェクトのメンバーに自動的になります。グローバル変数は、ウィンドウオブジェクトのプロパティです。グローバル関数は、ウィンドウオブジェクトの方法です。 */var name = "the Window"; //グローバル変数名を宣言し、この時点でグローバル変数名は自動的にウィンドウオブジェクトの属性になります時間グローバル変数オブジェクトオブジェクトは自動的にウィンドウオブジェクトの属性になりますvarオブジェクト= {name: "my object"、//オブジェクトの属性名getnamefunc:function(){// getnamefunc関数// getnamefunc falue of the getnamefuncメソッドのreturn value of object offcums retuble retubn function()オブジェクトとは、どのオブジェクトを指します。 //匿名関数でこれがオブジェクトアラートの代わりにウィンドウオブジェクトを表すことを証明します( "この==オブジェクトの結果は"+(this == object)); alert( "この==ウィンドウの結果は次のとおりです。"+(this == window)); this.name; //これはウィンドウオブジェクトを表すので、this.nameは自然にウィンドウオブジェクトの名前「ウィンドウ」}にアクセスします。 }}; //証明:グローバルオブジェクトオブジェクトは、ウィンドウオブジェクトの属性( "window.object:"+window.object); alert( "window.object.name:"+window.object.name);/*getnamefuncメソッドを呼び出した後、匿名メソッドが返されます。現時点では、retfnは匿名の方法を表します。これで、匿名の方法に名前をretfnに与えることに相当します。この時点で、retfn関数は自動的にウィンドウオブジェクトの関数になります*/var retfn = object.getnamefunc(); alert(retfn()); //返された匿名メソッドを呼び出します。これはウィンドウオブジェクトです//証明:retfn関数はウィンドウオブジェクトアラートの関数です( "window.retfn():"+window.retfn()); // window.retfn()(オブジェクト名。メソッド名)の形でretfnメソッドを呼び出すことができます。コードスニペット2:
分析は次のとおりです。
var name = "the Window"; //グローバル変数名//グローバルオブジェクトオブジェクトオブジェクトオブジェクト= {name: "my object"、getnamefunc:function(){/*この時点でこれを表しますか?これはオブジェクトオブジェクトを表します。どのオブジェクトがこれが位置する関数を呼び出しますか?これは、オブジェクトが実行されたオブジェクトを指し、それはオブジェクトオブジェクト*/varを表します。これは= this; // alert( "this == window result is:"+(this == window)); //それがオブジェクトオブジェクトアラートを表すことを証明します( "that == object result is:"+(that == object)); return function(){/*これは、getNameFUNC関数で宣言されたローカル変数です。通常の状況では、getNameFunc関数呼び出しが完了した後、JavaScriptのGCによってリサイクルされるローカル変数は、ローカル変数によって占有されているメモリスペースを解放しますが、現在は正常に使用でき、リサイクルされていません。その理由は、getNameFuncが匿名関数の親関数であるためです。 getNameFUNC関数が呼び出された後、匿名関数が返され、グローバル変数RETFNに割り当てられます。これにより、匿名関数が常にメモリになり、匿名関数の存在がgetNameFUNC関数に依存します。したがって、getNameFUNC関数は常にメモリにあり、コールが終了した後、ガベージコレクションメカニズムによってリサイクルされません。 getNameFUNC関数は常にメモリにあるため、getNameFUNC関数内で宣言されたローカル変数は常にメモリに存在します。それは存在するので、もちろんそれを使用し続けることができます。 */return that.name; //オブジェクトオブジェクトを表します。 }}; var retfn = object.getNameFunc(); // getNameFuncメソッドを呼び出した後、匿名メソッドが返されます。現時点では、retfnは匿名のメソッドを表します。これは、匿名の方法に名前を与えることと同等であり、retfn alert(retfn())です。最後に、以前にJavaScriptの閉鎖を学んだときに書いた例も添付しました。
<スクリプトタイプ= "text/javascript"> function a(){var i =; //ローカル変数I内部関数a/宣言b(){alert( "i ="+(++ i))関数b。 b。変数Iが使用されます。 c()を実行すると、ウィンドウがポップアップしてi(初めて)の値を表示し、このコードは実際に閉鎖を作成します。これは、関数Aの外側の変数Cが関数内関数aを指すためです。つまり、関数Aの内部関数Bが変数外部関数Aによって参照される場合、いわゆる「閉鎖」閉鎖が作成されます。 Aが実行されて返された後、閉鎖により、JavaScriptのガベージコレクションメカニズムGCはAが占有するリソースをリサイクルしません。これは、A(); //メモリにスペースがあるため、A(); A()が実行された後、GCはI var c = a(); //この使用法に割り当てられたメモリスペースをリサイクルします。GCはIをガベージとc(); // b()に相当しません。実行結果:
上記のコンテンツは、エディターが導入したJavaScriptの知識ポイント(16)のJavaScript閉鎖(閉鎖)コードの詳細な説明です。私はそれが誰にでも役立つことを願っています!