Javascript の入れ子関数と Closures_JavaScript スキルに関する簡単な説明
JavaScript では関数の埋め込みが可能であり、関数をデータとして使用することができ、関数の字句スコープの下で、従来のオブジェクト指向言語と驚くべき違いを生み出すことができます。
まず第一に、JavaScript 関数は動的ではなく字句的にスコープ設定されているため、関数は実行されるスコープではなく、定義されているスコープ内で実行されるため、ネストされた場合は簡単に理解できます。関数とその周囲の関数は同じ字句範囲内で定義されます。たとえば、次のような非常に当たり障りのないコード:
var x = 'グローバル';
関数 f () {
var x = 'ローカル';
関数 g() {
アラート(x); ();
}
f(); // 'local'
f() が呼び出されるとき、スコープ チェーンは呼び出しを含む 2 つの部分で構成されると理解できます。 f オブジェクトの後にグローバル オブジェクトが続きます。このとき、x の値を検索する場合は、まず f の呼び出しオブジェクトから検索され、見つからない場合は後続のグローバル オブジェクト内で x が検索されます。同様に、g は f の入れ子関数であるため、g が呼び出されるとき、スコープ チェーンは、g の呼び出しオブジェクト、f の呼び出しオブジェクト、およびグローバル オブジェクトの 3 つの部分で構成される必要があります。関数 g は x の値を出力するため、最初に g の呼び出しオブジェクトで x の値を検索します。次に、周辺の f 呼び出しオブジェクトで x の定義を検索します。 find x='local' の場合、グローバル オブジェクトの検索を続行する代わりに x を出力します。 x の値が f で定義されていない場合、スコープ チェーンの背後にあるグローバル オブジェクトの検索が続行され、結果はグローバルになります。グローバルオブジェクトで定義されていない場合は、当然未定義になります。
次に、クロージャが外部変数の値をメモリに保存できる理由を理解するのに役立つ、ありふれた例を見てみましょう。
}
var a = [makeFunc(0), makeFunc(1), makeFunc(2)];
alert(a[0]()); >alert( a[1]());
alert(a[2]());
実行結果は 0,1,2 です。字句スコープの厳密な通常の動作。各 makeFunc 呼び出しが完了すると、その呼び出し元オブジェクトはスコープ チェーンから削除され、そのオブジェクトへの参照はなくなり、最終的にはガベージ コレクションを通じて完了します。もっと詳しく言うと、このように理解できます。
makeFunc が呼び出されるたびに、呼び出し元のオブジェクトが作成され、スコープ チェーンに配置されます。関数 makeFunc の場合、呼び出し元オブジェクトには属性が含まれます。関数が実行されると、呼び出し元オブジェクトが作成され、スコープ チェーンに配置されます (注: 関数には x の定義がありません)。無名関数の呼び出しオブジェクトなので、その周囲の関数を参照します。 makeFunc の呼び出しオブジェクト (アクセスします。呼び出し元のオブジェクトには x が含まれているため、x が破棄されると x も破棄されます。保存されません。
}
var a = [ makeFunc()、makeFunc()、makeFunc()];
alert(a[0]());
alert(a[2]()); );
x はグローバル変数であり、実行結果は 0、1、2 ですが、この結果は上記とは多少異なります。次に、スコープチェーンの観点からこの結果の理由を理解します。
同様に、makeFunc が呼び出されるたびに、内部の入れ子関数への参照が返されるため、呼び出し元オブジェクトがスコープ チェーンに作成され、内部の入れ子関数が実行を開始し、入れ子関数の呼び出しオブジェクトを作成します。スコープチェーン。次に、x の値を返します。ここでは、入れ子になった関数の呼び出しオブジェクトには x がなく、その周囲の makeFunc の呼び出しオブジェクトには x がありません。検索できるのはグローバル オブジェクトまでだけです。グローバル オブジェクト内で x の定義が見つかったので、通常どおり実行され、x の値が返され、x が 1 ずつ増分され、ネストされた関数が完了し、呼び出し元のオブジェクトが削除され、makeFunc が完了します。呼び出し元のオブジェクトも削除されますが、呼び出し元のオブジェクトには x がないため、呼び出し元のオブジェクトの破棄は x にまったく影響しません。その結果、グローバル変数 x の値の変更が保存されます。
外部呼び出しオブジェクトへの上記のアクセスは理解を助けるためのものであり、厳密なものではないことに注意してください。ただし、JavaScript が定義するプロパティはスコープ チェーンの一部です。呼び出しオブジェクトはまだ「生きています」。さらに、周辺関数にグローバル オブジェクトへの参照を持つ 2 つ以上の入れ子関数が含まれている場合、これらの入れ子関数はすべて同じグローバル呼び出しオブジェクトを共有し、そのうちの 1 つによるグローバル オブジェクトへの変更は他の関数にも表示されます。の。
JavaScript では、関数は、実行されるコードと、これらのコードが実行されるスコープで構成される複合体です。大まかに言えば、このコードとスコープの複合体をクロージャーと呼ぶことができます。
【終わり】
変数の値を記憶するために呼び出す必要がある関数を記述する必要がある場合があります。したがって、スコープを理解していれば、関数の呼び出しオブジェクトは呼び出し後に維持できないため、ローカル変数を実現するのが難しいことがわかります。上の例のように、グローバル変数でこれを行うことができますが、これは簡単にグローバル変数汚染を引き起こす可能性があります。呼び出し元のオブジェクトは維持できないので、呼び出し元のオブジェクトに値を保存すればよいのではないでしょうか? !したがって、これを行う 1 つの方法は、関数オブジェクト自体のプロパティとともに保存することです。
uniqueID = function () {
if (! argument.callee.id) argument.callee.id = 0;
return argument.callee.id ;
alert(uniqueID()); //0
alert(uniqueID) ()) ; //1
したがって、通常、これを達成するためにクロージャを使用します。次のように:
var id = 0;
return function () {return id }
})();
alert(_uniqueID()) //0
alert(_uniqueID()); ; //1
混乱している人もいるかもしれませんが、関数の実行後に呼び出し元のオブジェクトがスコープ チェーンを削除したということではないでしょうか?呼び出し元のオブジェクトにはあってはならないのです。
はい、呼び出し元のオブジェクトは現在の関数が実行された後に参照を終了しますが、上記の _uniqueID() 呼び出しは直接呼び出された周辺関数ではなく、ネストされた関数が呼び出されたものであることを誤解しないでください。関数のセットには、周囲の関数のスコープ チェーンが含まれます。したがって、呼び出し元のオブジェクトがスコープ チェーンを削除すると、このスコープ チェーン内の他のオブジェクトのプロパティにアクセスして変更できます。
クロージング自体は理解するのが難しいですが、困っている人の助けになれば幸いです。また、資格が限られているため、私の理解が間違っている可能性があります。見つけた場合は修正してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック

C++ では、クロージャは外部変数にアクセスできるラムダ式です。クロージャを作成するには、ラムダ式の外部変数をキャプチャします。クロージャには、再利用性、情報の隠蔽、評価の遅延などの利点があります。これらは、イベント ハンドラーなど、外部変数が破棄されてもクロージャが外部変数にアクセスできる現実の状況で役立ちます。

クロージャは、外部関数のスコープ内の変数にアクセスできる入れ子関数です。その利点には、データのカプセル化、状態の保持、および柔軟性が含まれます。デメリットとしては、メモリ消費量、パフォーマンスへの影響、デバッグの複雑さなどが挙げられます。さらに、クロージャは匿名関数を作成し、それをコールバックまたは引数として他の関数に渡すことができます。

C++ ラムダ式は、関数スコープ変数を保存し、関数からアクセスできるようにするクロージャーをサポートしています。構文は [キャプチャリスト](パラメータ)->戻り値の型{関数本体} です。 Capture-list は、キャプチャする変数を定義します。[=] を使用してすべてのローカル変数を値によってキャプチャするか、[&] を使用してすべてのローカル変数を参照によってキャプチャするか、[variable1, variable2,...] を使用して特定の変数をキャプチャできます。ラムダ式はキャプチャされた変数にのみアクセスできますが、元の値を変更することはできません。

タイトル: クロージャによって引き起こされるメモリ リークと解決策 はじめに: クロージャは JavaScript における非常に一般的な概念であり、内部関数が外部関数の変数にアクセスできるようにします。ただし、クロージャを誤って使用すると、メモリ リークが発生する可能性があります。この記事では、クロージャによって引き起こされるメモリ リークの問題を調査し、解決策と具体的なコード例を提供します。 1. クロージャによるメモリリーク クロージャの特徴は、内部関数が外部関数の変数にアクセスできることです。つまり、クロージャ内で参照される変数はガベージコレクションされません。不適切に使用すると、

関数ポインタとクロージャが Go のパフォーマンスに与える影響は次のとおりです。 関数ポインタ: 直接呼び出しよりわずかに遅くなりますが、可読性と再利用性が向上します。クロージャ: 一般に遅いですが、データと動作をカプセル化します。実際のケース: 関数ポインターは並べ替えアルゴリズムを最適化でき、クロージャーはイベント ハンドラーを作成できますが、パフォーマンスの低下をもたらします。

クロージャでのメモリリークを防ぐにはどうすればよいでしょうか?クロージャは JavaScript の最も強力な機能の 1 つであり、関数のネストとデータのカプセル化を可能にします。ただし、クロージャでは、特に非同期やタイマーを扱う場合にメモリ リークが発生する傾向があります。この記事では、クロージャでのメモリ リークを防ぐ方法を説明し、具体的なコード例を示します。メモリ リークは通常、オブジェクトが不要になったにもかかわらず、そのオブジェクトが占有しているメモリを何らかの理由で解放できない場合に発生します。クロージャ内で、関数が外部変数を参照する場合、これらの変数は

Java のクロージャを使用すると、外部関数が終了した場合でも、内部関数が外部スコープの変数にアクセスできるようになります。匿名の内部クラスを通じて実装されると、内部クラスは外部クラスへの参照を保持し、外部変数をアクティブに保ちます。クロージャによりコードの柔軟性が向上しますが、匿名の内部クラスによる外部変数への参照により、それらの変数が存続するため、メモリ リークのリスクに注意する必要があります。

はい、コードの単純さと読みやすさは、連鎖呼び出しとクロージャーによって最適化できます。連鎖呼び出しは、関数呼び出しを流暢なインターフェイスにリンクします。クロージャは再利用可能なコード ブロックを作成し、関数の外の変数にアクセスします。
