私は以前、JavaScript クロージャとは何ですか? についてクロージャの理解について記事を書きました。これは非常に明確で、クロージャの理由を簡単に理解できると思います。私はチェーンとアクティブ オブジェクトだけがクロージャを本当に理解できると皆が言いました。その後、会社の同僚とコミュニケーションを取ったときに、スコープと実行環境が実際に非常に重要であることがわかりました。これらは JavaScript クロージャを理解するのに非常に役立つので、スコープと実行環境についての記事を書きました。
範囲
スコープは、変数と関数のアクセス可能なスコープであり、変数と関数の可視性とライフサイクルを制御します。JavaScript では、変数のスコープにはグローバル スコープとローカル スコープがあります。
一部の C に似たプログラミング言語では、中括弧内の各コードには独自のスコープがあり、変数は宣言されているコード セグメントの外では見えません。 JavaScript には、ブロック レベルのスコープはなく、関数レベルのスコープしかありません。変数は、宣言されている関数本体とサブ関数内で認識されます。
関数内で宣言されていないか、var なしで宣言されている変数はグローバル変数です。ウィンドウ オブジェクトのすべてのプロパティは、コード内のどこからでもアクセスできます。変数はローカル変数であり、関数本体内でのみ使用できます。関数のパラメーターは var を使用しませんが、それでもローカル変数です。
グローバル実行環境は、Web ブラウザーではウィンドウ オブジェクトであるため、すべてのグローバル変数と関数はウィンドウ オブジェクトの属性と増幅として作成されます。各関数には独自の実行環境があります。実行フローが関数に入ると、関数環境は関数スタックにプッシュされ、実行環境はスタックからポップされて、すべての情報が破棄されます。その後、変数と関数の定義は破棄され、アプリケーションが終了する (ブラウザが閉じる) まで、制御は前の実行環境に戻ります。
スコープチェーン
環境内でコードが実行されると、実行環境がアクセスできる変数と関数に順序よくアクセスできるように、変数オブジェクトのスコープ チェーン (sc) が作成されます。スコープ内の最初のオブジェクトは常に、コードが現在実行されている環境の変数オブジェクト (VO) です
実行環境が関数の場合、そのアクティベーション オブジェクト (AO) がスコープ チェーンの最初のオブジェクトとして使用され、2 番目のオブジェクトが包含環境、次のオブジェクトが包含環境の包含環境になります。 。 。 。 。
関数の実行中、識別子の解決は、最初のオブジェクトから開始して、同じ名前の識別子が見つかるまで段階的に遡って検索するプロセスです。トラバースを続行し、見つからない場合はエラーを報告する必要はありません。
クロージャをもう一度見てみましょう
以前のブログでは、内部関数を呼び出す可能性がある限り、JavaScript は参照された関数を保持する必要があると結論付けていました。さらに、JavaScript ランタイムは、JavaScript ガベージ コレクターが対応するメモリ領域を解放する前に、最後の変数が破棄されるまで、この内部関数を参照するすべての変数を追跡する必要があります。振り返ってみると、親関数で定義された変数は子関数のスコープ チェーン内にあり、子関数が破棄されなければ、そのスコープ チェーン内のすべての変数と関数が維持され、破棄されません。 。
内部関数 (クリック イベント ハンドラーはいつでも呼び出すことができる) のため、そのスコープ チェーンは破棄できません (言うまでもなく、この例では i はグローバル スコープ内にあり、ページが更新されたときにのみ破棄できます) i の値 for ループが実行された後の長さの値は常に維持されるため、onclick がトリガーされるたびに長さが警告されます。
ついに
実際、実行環境とスコープ チェーンを理解すると、クロージャは明らかになりますが、上記の例からわかるように、クロージャはサブ関数にすべての変数、関数のスコープ チェーンを維持させます。メモリは大量のメモリを消費します。親関数で使用されなくなった変数は、使用するときに破棄してください。