導入例示する この記事では、JavaScript クロージャの役割、目的、原則について説明します。 閉鎖の定義 クロージャとは、内部関数が外部関数内でも常に外部関数で宣言された変数とパラメータにアクセスできることを意味します。 番号が返却された後(有効期限が切れます)。 クロージャの役割(特徴) 1. 関数内の関数 2. 内部関数は外部関数のパラメータや変数を参照できる 3. 外部関数のパラメータと変数は内部関数によって参照されるため、ガベージコレクションの対象になりません。 クロージャとグローバル変数 クロージャの使用カレー作りパラメータを通じてさまざまな関数を生成できます。 関数makeWelcome(x) { 関数(y)を返す{ x + y を返します。 }; } sayHello = makeWelcome("Hello,") とします。 sayHi = makeWelcome("Hi,") とします。 console.log(sayHello("Tony")); console.log(sayHi("Tony")); 結果
パブリック変数の実装要件: 呼び出されるたびに 1 回増加するアキュムレータを実装します。 関数makeCounter(){ count = 0 とします。 関数 innerFunction(){ count++ を返します。 } 内部関数を返します。 } カウンターを makeCounter() にします。 コンソールにログ出力します。 コンソールにログ出力します。 コンソールにログ出力します。 結果
キャッシュ処理に非常に時間のかかる関数オブジェクトがあるとします。計算された値は保存できます。この関数が呼び出されると、まずキャッシュ内で検索されます。見つからない場合は計算が行われ、キャッシュが更新されて値が返されます。見つかった場合は、見つかった値が直接返されます。 クロージャは外部参照を解放しないため、関数内の値を保持できるため、これを実行できます。 簡潔にするために、この記事では読み取り/書き込みキャッシュの例を直接記述します。 (読み取れない場合は計算してキャッシュに保存する代わりに)。 キャッシュ = 関数 () { // マップでは任意のタイプのキーを使用できます。 let storage = {} と記述した場合、キーには文字列のみを指定できます。let storage = new Map(); 戻る { setCache: 関数(k, v) { ストレージ[k] = v; }, getCache: 関数 (k) { ストレージ[k]を返します。 }, キャッシュを削除する: 関数 (k) { ストレージ[k]を削除します。 } } }(); キャッシュをsetCache('a', 1); コンソールログ(キャッシュの取得キャッシュ('a')) 結果
カプセル化(属性のプライベート化)内部変数には、提供されたクロージャを通じてのみアクセスできます。 (この方法は良くないので、プロトタイプチェーンを使用することをお勧めします)。 person = function(){ とする // 変数のスコープは関数内にあり、外部からアクセスすることはできません。let name = "defaultName"; 戻る { getName: 関数(){ 名前を返します。 }, setName: 関数(newName){ 名前 = 新しい名前; } } }(); console.log(人名); コンソールにログ出力します。 person.setName("こんにちは"); コンソールにログ出力します。 結果
閉鎖の原則カウンターを例に挙げてみましょう: 関数makeCounter() { count = 0 とします。 関数()を返す{ count++ を返します。 }; } カウンターを makeCounter() にします。 コンソールにログ出力します。 コンソールにログ出力します。 コンソールにログ出力します。 結果
各 makeCounter() 呼び出しの開始時に、その makeCounter ランタイムの変数を格納するための新しい LexicalEnvironment オブジェクトが作成されます。 したがって、ネストされた語彙環境には 2 つのレベルがあります。 makeCounter() を実行すると、1 行だけを占めるネストされた関数 return count++ が作成されます。まだ実行していません。作成しただけです。 すべての関数は、それが「誕生」したときに作成された語彙環境を記憶します。理由: すべての関数には、関数が作成された語彙環境への参照を保持する [[Environment]] と呼ばれる隠し属性があります。 したがって、counter.[[Environment]] には {count: 0} 字句環境への参照があります。これは、関数が呼び出される場所に関係なく、関数が作成された場所を記憶する方法です。 [[Environment]] 参照は関数の作成時に設定され、永続的に保存されます。 その後、counter() が呼び出されると、その呼び出しに対して新しい Lexical Environment が作成され、その外部 Lexical Environment 参照が counter.[[Environment]] から取得されます。 ここで、counter() 内のコードが count 変数を探すとき、最初に自身の Lexical Environment (ローカル変数がないため空) を検索し、次に外側の makeCounter() の Lexical Environment を検索して、見つかった場所に count 変数を固定します。 変更します (変数が存在する語彙環境内の変数を更新します)。 実行後のステータスは次のとおりです。 counter() を複数回呼び出すと、count 変数は同じ位置で 2、3 などに増加します。 ガベージコレクション導入通常、関数呼び出しが完了すると、レキシカル環境とその中のすべての変数は、参照がなくなるためメモリから削除されます。 JavaScript の他のオブジェクトと同様に、語彙環境はアクセス可能である限りメモリ内に保持されます。ただし、関数が終了した後もまだ到達可能なネストされた関数がある場合、その関数には、Lexical Environment を参照する [[Environment]] 属性があります。 関数が完了した後も、レキシカル環境がまだ到達可能である場合、ネストされた関数は有効なままになります。例えば: 関数f(){ 値を 123 とします。 関数()を返す{ アラート(値); } } // g.[[Environment]] は対応する f() 呼び出しの語彙環境への参照を格納します。let g = f(); f() が複数回呼び出され、返された関数が保存されると、対応するすべての LexicalEnvironment オブジェクトもメモリ内に保持されます。例えば: 関数f(){ 値を Math.random() とします。 関数を返す(){ アラート(値); }; } // 配列内の 3 つの関数。それぞれが対応する f() の語彙環境に関連付けられています。let arr = [f(), f(), f()]; LexicalEnvironment オブジェクトが到達不能になると、他のオブジェクトと同様に終了します。つまり、少なくとも 1 つのネストされた関数がそれを参照している限り存在します。 次のコードでは、ネストされた関数が削除されると、それを囲むレキシカル環境 (およびその中の値) もメモリから削除されます。 関数f(){ 値を 123 とします。 関数()を返す{ アラート(値); } } let g = f(); // g関数が存在する間、値はメモリに保持されます g = null; // これでメモリがクリーンアップされます 実際の開発における最適化これまで見てきたように、理論上は関数が到達可能である場合、その外側にあるすべての変数も存在することになります。しかし実際には、JavaScript エンジンはそれを最適化しようとします。変数の使用状況を分析し、未使用の外部変数があることがコードから明らかな場合は、それらが削除されます。 V8 (Chrome、Opera) での重要な副作用は、そのような変数がデバッグで使用できなくなることです。 Chrome ブラウザの開発者ツールを開き、次のコードを実行してみてください。 関数f(){ 値を Math.random() とします。 関数g(){ デバッガ; } g を返します。 } g = f() とします。 g(); コードが「debugger;」の場所まで実行されると一時停止します。このとき、コンソールに console.log(value); と入力します。 結果: エラー: VM146:1 キャッチされない参照エラー: 値が定義されていません これにより、興味深いデバッグの問題が発生する可能性があります。たとえば、予想される変数の代わりに、同じ名前の外部変数が表示されることがあります。 let value = "サプライズ!"; 関数f(){ value = "最も近い値"; 関数g(){ デバッガ; } g を返します。 } g = f() とします。 g(); コードが「debugger;」の場所まで実行されると一時停止します。このとき、コンソールに console.log(value); と入力します。 結果: 出力: 驚き。 以上がJavaScriptクロージャの原理と機能の詳細な内容です。JavaScriptクロージャの詳細については、123WORDPRESS.COMの他の関連記事に注目してください。 以下もご興味があるかもしれません:
|
<<: tomcat ログ ディレクトリ内のログ ファイルの分析 (概要)
目次序文グローバルロックテーブルロックテーブルロックメタデータ ロック (MDL ロック)要約する参...
前回の記事では、MySQL ステートメントの実行時間をチェックする 2 つの方法を紹介しました。今日...
pthread_create関数機能紹介pthread_createはUNIX環境のスレッド作成関数...
今日、研究室のプロジェクトを見ていたとき、私にとって「難しい」問題に遭遇しました。実は、それは私があ...
最近、IM を実行するときに、これらの 3 つのキーワードを同時に使用したときに問題が発生しました。...
1 はじめにデータベースを設計する場合、画像や音声ファイルをデータベースに挿入することは避けられませ...
最近、同社はitpubを皮切りに、コーポレートウェブサイト傘下の全サイトの評価を開始した。そのために...
個人アカウントのパスワードを変更する一般ユーザーが個人アカウントのパスワードを変更する場合は、他のコ...
環境準備: VMware+CentOS、jdk 1. システムディスクのサイズを確認する1. コマン...
この方法は、CSS3のdrop-shadow filterを使用して、png画像の不透明部分に任意の...
1. システム環境yum updateアップグレード後のシステムバージョンは[root@yl-web...
このブログを書くつもりはなかったのですが、実際の操作中に、ネットワークの問題に圧倒されたこと (ネッ...
現在このような問題が発生しています 私の状況は、QT が動かなくなってしまったため、仮想マシンを再起...
序文職場で次のような状況に遭遇しました。ログ システムのテーブルでは、時間フィールドには日付データで...
CentOS 7 では、次のようなコマンドを使用してホスト ポートをコンテナー ポートにマッピングす...