<JavaScriptの>闭包(閉鎖)

JS閉鎖(閉鎖)

クロージャ(閉鎖は)難しい言語は、Javascriptが、それはまた、多くの高度なアプリケーションは、クロージャを達成するために頼らなければならない特徴です。
ここではJavascriptの初心者のための私の研究ノートは非常に便利であるべきです。

A.クロージャとは何ですか

JS、関数は、関数外で内部変数を読み込み

関数外(){ 
     VARのlocalVal = 30。
     localValを返します。
} 
外側(); // 30

しかし、外部関数は、自然に関数内のローカル変数を読み取ることができません

関数外(){ 
     VARのlocalVal = 30。
} 
アラート(localVal); //エラー

あなたが関数内で変数を宣言する際に、VaRのコマンドを使用してください、注意を払う必要があります。そうでない場合は、それが実際にグローバル変数が宣言されています。

コードをコピー
関数外(){ 
     localVal = 30。
     localValを返します。
} 
外側();
警告(localVal); // 30
コードをコピー

上記式は、グローバルおよびローカル変数を含むJS変数のスコープの知識。

そんなに特別なJavascriptの言語は、内部関数のグローバル変数を直接読み取ることができるということです。

コードをコピー
関数外(){ 
     VARのlocalVal = 30。
関数内(){ 
          アラート(localVal)。
     }
     インナー返す; 
} 
外側のvar FUNC =(); 
FUNC(); // 30
コードをコピー

我々は、上記のコードでは、内側および外側の関数は内側の関数が出て警告localVal、機能内側、外側の関数の戻り値は、内部関数で定義する参照します。

私たちは、上記のコードの特徴を見ることができます:機能ネストされた関数は、内部関数はガベージコレクションのメカニズムを回復することはありません外部関数のパラメータや変数、パラメータや変数を参照することができます。

閉鎖された内部コード機能、。簡潔には、閉鎖(クロージャ)は、内部機能の他の変数の関数を読み取ることができます。

JavaScript言語、ローカル変数を読み込むための唯一の内部関数サブルーチンので、クロージャは、単に「関数内で定義された関数。」と解釈することができます したがって、本質的に、クロージャは、内部ブリッジ機能と外部接続の機能です。

上記のコードでは、関数は、外側内のすべてのローカル変数は、内側のペアが表示され、内側外側の関数の内部に含まれています。しかし、OUTE内部内部のローカル変数は表示されません。これは、JavaScriptの言語固有の「スコープチェーン」構造(チェーン・スコープ)で、子オブジェクトは、すべての親の変数オブジェクトへのより高いレベルを探します。だから、すべての変数の親オブジェクトは、子オブジェクトが表示され、その逆はありません。

機能は補足で定義されている--JS

JS関数を定義し、それが最も一般的に使用される関数宣言と関数式であります

関数宣言のJSは、以下の形態を指します。

関数functionnameと(){   
  
}

関数式は、関数を宣言するので、同様の表現です。

VAR functionnameと=関数(){   

}

私たちは、関数式を使用して関数を作成し、そのように、すぐにそれを実行することができます。

(関数(){ 
  VARのA、B //ローカル変数
  // ... //およびコード
})()

()();まず括弧は無名関数を置きます。

両者の違い:宣言と関数式を機能させるJSパーサは同等に扱われていません。関数宣言の場合は、JSパーサは、任意のコードが実行される前に文が解決されていることを確認するために、優先順位を読み込み、変数の他の基本的な型として定義されている関数式は、実行にのみ解決されるときに1そのため、実際には、彼らはまだ違いがあり、特に関数を定義する関数宣言の形式を使用しているときに、次の文を呼び出すことができますこれを行うには、関数の宣言の前に記述され、後者たエラーになります。

II。クロージャ

クロージャを使用する利点:

- それらの変数メモリの長期的な存在にしたいです。

- グローバル変数の汚染を避けるために、

- プライベートメンバーの存在

1.モジュラーコード

アナログブロックレベルの範囲によって行わ匿名関数の使用から

(関数(){ 
        //ここでブロックレベルのスコープ
 })();

この方法は、多くの場合、グローバルスコープにグローバルスコープの変数と関数の影響を制限するようにあまりにも多くを追加し、グローバルスコープ外部関数で使用されています。また、匿名関数は何の変数のポイントを持っていないので、あなたはすぐにそのスコープチェーンを破壊することができます終了し、メモリの使用量としてクロージャを減らすことができます。

例:

コードをコピー
VARテスト=(関数(){ 
    VARのA = 1; 
    return関数(){ 
        ++; 
        アラート(A); 
    } 
})(); 

テスト(); // 2 
テスト(); // 3
コードをコピー

自主の実現は、グローバルを汚染しません。

2.閉鎖サイクル

各に対するLiの循環が警告番号をクリックして、クリックイベントを登録しました。コードは以下の通りであります:

コードをコピー
VAR ALI = document.getElementByClassName( "試験")。
関数showAllNum(ALI){ 
    のために(VAR I = 0、LEN = aLi.lengthを、私がlen <;私は++){ 
            アリ[i]を.onclick =機能(){ 
            警告(I); //すべてのaLi.lengthをしています!
        } 
    } 
}
コードをコピー

クリックすると、代わりに123の値aLi.lengthでポップアップ表示されます。サイクルが終了したクリックする前に、私はaLi.lengthです。

、メモリ内の各Iの存在匿名関数を構築するために閉鎖を使用する、 Iの抽出された値は、外部の匿名関数で関数をonclickの、。コードは以下の通りであります:

コードをコピー
VAR ALI = document.getElementByClassName( "試験")。
関数showAllNum(ALI){ 
    ため(VAR I = 0、LEN = aLi.length; iがLEN <; iは++){ 
        (関数(I){ 
            アリ[I] .onclick =関数(){ 
            アラート(I); 
        } 
        } )(私); 
    } 
}
コードをコピー

または:

コードをコピー
関数showAllNum(ALI){ 
    ため(VAR I = 0、LEN = aLi.length; iがLEN <; iは++){ 
            アリ[I] .onclick =(関数(I){ 
                return関数(){ 
                    アラート(I); 
                } 
            })(私); 
    } 
}
コードをコピー

インタプリタを実装します:

1.スコープチェーン

2.閉鎖割り当て機能と操作

実際には唯一の割り当て表のスタイル機能のラベルをクリックしてイベントを経由して支払われ、動作していない、完成を横断するとき、私は私の機能にするためにアップを見つけるために、原則の範囲に応じて、標識基の長さになるので、クリックしてくださいラベルの時間長の実装では、グループをポップアップ表示されます。クロージャは、それらの変数メモリに長期の存在を引き起こす可能性があり、我々はそれ自己実行させるすべての変数への結合事象は、メモリに格納されている場合、実行時間がこの範囲のI対応する番号をポップアップ表示されますクリックしてください。

3.パッケージ

関数内で外部変数に連絡することができない、露光の方法により得ることができます

コードをコピー
VAR情報=関数(){ 
    VAR _userId = 23492。
    VaRの_typeId = 'アイテム'; 

    getUserId(){機能
        アラート(_userId)を、
    } 

    関数getTypeId(){ 
        アラート(_typeId)。
    } 
}。

info.getUserId(); // 23492 
info.getTypeId(); //アイテム

info._userId //未定義
info._typeId //未定義
コードをコピー

しかし、このアプローチは、すべての時間では、新しいオブジェクトを作成するときに、このような方法を作成するために私たちをリードします。さまざまな方法で作成された各インスタンスを避けるため、プロトタイプを作成するには、このメソッドを使用します。ここに入る(通常はコンストラクタ性質を持って、プラスプロトタイピング法)ではありません。

このテーマに関しては4

これは、(匿名関数がグローバルである)(この:イベントが発生し、現在の要素)のランタイム実行環境機能バインディングでオブジェクトに基づいており、時には、少し明らかにいくつかの例の閉鎖に。

コード1:

コードをコピー
VAR名=「ウィンドウ」。
VAR OBJ = { 
    名: "オブジェクト"、
    getNameFunc:関数(){ 
        return関数(){ 
            this.nameを返します。
        } 
    } 
} 
警告(OBJ。getNameFunc()は())ウィンドウ//します
コードをコピー

コード2:

コードをコピー
VAR名= "ウィンドウ" 
VAR OBJ = { 
    名: "オブジェクト"、
        
    getNameFunc:関数(){ 
        VARの_this =この; 
        復帰機能(){ 
            戻り_this.name。
        } 
    } 
} 
警告(object.getNameFunc()()); //オブジェクト
コードをコピー

Javascriptをこのキーは、それが誰であるかの実行時に決定することができ、動的な(または動的型付け)の言語です。だから、これは常に呼び出し側を指すようになります、それは「オブジェクトを呼び出す」のへの参照です。コードを介して第一の部分:新しい関数を返す実行コードobject.getNameFunc()、これはオブジェクトと関数オブジェクトではないことに注意した後、グローバル関数として理解することができ、それはこの時点で呼び出される、オブジェクトのプロパティまたはメソッドではありません誰が窓なので、出力はウィンドウです。

第二の部分は、関数が実行されるobject.getNameFunc()戻り値:

関数()
{ 
         戻り_this.name。
}

この時間_thisで=これ。そして、これはポイントオブジェクトになるように、オブジェクトを指します。彼は、参照オブジェクトであるため、出力マイオブジェクト。

概要:この中JSについて、呼び出すために誰が覚えている、これは誰を指し、この閉鎖にアクセスするには、キャッシュされた変数を定義します。一般のvar _this =このような。

IE 5.閉鎖メモリリーク

IE9、JScriptのオブジェクトと異なるガベージコレクションのルーチンを使用してCOMオブジェクトに先立ち、その後、閉鎖はいくつかの問題が発生します。

クロージャを作成し、閉鎖はその要素が破壊されることはありません、循環参照を作成しました。一般的なプロパティは、再び自分の属性を呼び出して取得したり、DOM要素の配列(またはメソッド)です。例えば:

コードをコピー
機能ハンドラ(){ 
    VARのELE =のdocument.getElementById( "ELE")。
    ele.onclick =関数(){ 
        アラート(ele.id)。
    } 
}
コードをコピー

イベントオブジェクト全体を通して参照クロージャは閉鎖ELEへの直接参照ではない関数は、アクティブなオブジェクトがまだメモリを解放するために、null参照を切断することができ、設定を保存し、それへの参照が保存されますが含まれています。コードは以下の通りであります:

コードをコピー
機能ハンドラ(){ 
    VARのELE =のdocument.getElementById( "ELE")。
    VaRのID = ele.id。
    ele.onclick =関数(){ 
        アラート(ID)。
    } 
    ELE = NULL; 
}
コードをコピー

もちろん、他の方法があり、この方法が推奨されます。

III。原理閉鎖

関数が最初に呼び出されるとき、それは実行環境(実行コンテキスト)と、適切なスコープチェーン、及び特別な内部プロパティ(すなわち、[範囲])を割り当てるスコープチェーンが作成されます。次いで、これを使用して、アクティブなオブジェクトの機能(活性化オブジェクト)を初期化するために他の名前付きの値およびパラメータをarguncmts。しかし、スコープチェーンに、外部関数へのアクティブなオブジェクトが常に二位になり、アクティブは、グローバルスコープチェーンの実行環境として最後まで......、外部関数外部関数が第三位であるオブジェクト。

関数の実行時には、読み取りと書き込みの変数の値は、スコープチェーンの変数を見つけることが必要です。次の例を考えてみます。

コードをコピー
機能比較(valael、値2){ 
    IF(valuel <値2){ 
       -1を返します。
    }そうであれば(vaiuel>値2){
       1返す; 
     }そうでなければ{ 
       0を返します。
    } 
} 

VAR結果=(5、10)を比較します。
コードをコピー

上記のコードでは、最初の比較()関数を定義し、そして、グローバルスコープでそれと呼ばれます。最初の呼び出し)は(比較したとき、それが含まれ、この、引数、valuelとvalue2アクティブオブジェクトを作成します。グローバル変数オブジェクト実行環境比較()スコープチェーン実行環境が第2の位置にある(これを含むが、結果と比較されたいです)。図含めて実行スコープチェーン中の比較()関数との関係を示します。

画像

可変オブジェクト - それぞれの実行環境は、背景オブジェクトを表す変数を持っています。地球環境の変数オブジェクトは常に存在しますが、変数、オブジェクト、そのようなローカル環境のような比較()関数は、唯一の機能の実行の過程でもあります。作成比較()関数は、所定のスコープチェーンは、子オブジェクトがグローバルになる含ま作成すると、それは内部のスコープチェーン[範囲]プロパティに格納されています。比較呼び出すとき()関数は、関数の実行環境を作成し、関数オブジェクトの[[範囲]プロパティをコピーすることにより、スコープチェーンの実行環境を構築します。それ以来、(可変オブジェクトとしてここで使用される)アクティブ・オブジェクトが作成され、スコープチェーン実行環境の前方に押し込みます。アクティブオブジェクトおよびグローバル変数ローカルオブジェクト:この例では、実行環境は、スコープチェーンは、2つの可変オブジェクトを含む()関数を、比較します。明らかに、スコープチェーンは、本質的に変数オブジェクトへのポインタポイントのリストですが、実際には変数オブジェクトを参照含まれていません。

関数内の変数へのアクセスがあるたびに、それはスコープチェーンからの適切な名前を持つ変数を検索します。一般に、関数が終了すると、ローカルアクティブオブジェクトのみグローバルスコープ(グローバル実行環境の変数オブジェクト)メモリに格納され、破壊されます。しかし、状況クロージャは異なっています。

コードをコピー
関数createComparisonFunction(プロパティ名){ 
  return関数(物体1、オブジェクト2){ 
    VAR valuel = objectl [プロパティ名]。
    VaRの値2 =オブジェクト2 [プロパティ名]。
    IF(valuel <値2){ 
       戻り-1。
    }(valuel>値2)は{他の場合に
       1を返します。
    }他{ 
       戻り0; 
     } 
  }; 
}
コードをコピー

関数は、別の関数の内部で定義されたアクティブ・オブジェクトは、そのスコープチェーンに追加された機能(すなわち、外部関数)を含むセット。したがって、対数スコープチェーン匿名暗渠内部のcreateComparisonFunction()関数が定義され、実際には、外部関数createComparisonFunction()アクティブオブジェクトを含むであろう。次の図は、コードが実行されることを示す場合、機能匿名関数を含むスコープチェーンの内部を有します。

VAR = createComparisonFunction( "名前")を比較します。

VaRの結果=比較({名"ニコラス"}、{naine:BGreg」})。

無名関数は、()jiongがcreateComparisonFunctionから返された後、そのスコープチェーンがアクティブなオブジェクトとグローバル変数に初期化され、目的関数は)(createComparisonFunctionが含まれています。このように、無名関数はcreateComparisonFunctionに()すべての変数が定義されているアクセスすることができます。匿名関数スコープチェーンがアクティブオブジェクトへの参照のままであるので、より重要なことは、その活動の実施オブジェクト後createCoir.parisonFunction()関数が破壊されないであろう。換言すれば、場合createComparisonFunction()関数が返す、その範囲鎖実行環境が破壊され、それはまだメモリ内にアクティブなオブジェクトのままで、匿名関数が破壊された後、createComparisonFunction()は、アクティブなオブジェクトになりまでそれは、例えば、破壊されています。

コードをコピー
; createComparisonFunction compareNames = VAR( "名前")

//呼び出し関数
、{名:VaRのcompareNamesは=( "ニコラス" {名):結果が"グレッグ"}); 

//が解放(メモリを解放するために)匿名関数への参照
compareNanies = NULL;
コードをコピー

まず、比較関数はcoinpareNamesで作成した変数に格納されます。そして、関数参照を解放するためにnullに等しく設定compareNamesによって、それがガベージコレクションのルーチンを通知することと等価である、それをクリアするために尋ねました。匿名関数スコープチェーンが破壊されると、(Rグローバルスコープを除く)他のスコープも安全に破棄することができます。図は、プロシージャのスコープチェーンの関係はconpareNamesO発生コール示します。

画像

-------------------------------------------------- -------------------------------------------------- ---------------------------------

クロージャーは、それを理解することは非常に重要である、どこにでもあります。

おすすめ

転載: www.cnblogs.com/isAndyWu/p/11495777.html