ホームページ  >  記事  >  ウェブフロントエンド  >  javascript クロージャ_javascript スキル

javascript クロージャ_javascript スキル

WBOY
WBOYオリジナル
2016-05-16 18:02:08950ブラウズ

初心者にとって Javascript クロージャを理解するのはまだ難しいです。この記事を書く目的は、最も一般的な言葉を使って Javascript クロージャの本当の姿を明らかにし、初心者にも理解しやすくすることです。
1. クロージャとは何ですか?
「公式」の説明は次のとおりです。クロージャは、多くの変数とこれらの変数にバインドされた環境を持つ式 (通常は関数) であり、したがって、これらの変数も式の一部です。あまりにも学術的な記述のため、この文章を直接理解できる人は少ないと思います。
実際、この文は平たく言えば、JavaScript のすべての関数はクロージャであることを意味します。しかし、一般的に言えば、入れ子関数によって生成されたクロージャはより強力であり、ほとんどの場合、これを「クロージャ」と呼びます。次のコードを見てください。

コードをコピー コードは次のとおりです。

function a( ) {
var i = 0;
function b() {
alert( i);
}
return b;
var c = a();
c();


このコードには 2 つの特徴があります:
1. 関数 b は関数 a 内にネストされています。
2. 関数 a は関数 b を返します。
このように、var c=a() を実行すると、変数 c は実際には関数 b を指します。変数 i は b で使用されます。c() を実行すると、i の値を表示するウィンドウが表示されます。時間は1)です。このコードは実際にクロージャを作成します。なぜでしょうか。関数 a の外側の変数 c は関数 a の内側の関数 b を参照しているため、
関数 a の内部関数 b が関数 a の外側の変数によって参照される場合、いわゆる「クロージャ Bag」が作成されます。 」。もう少しわかりやすく言いましょう。いわゆる「クロージャ」とは、コンストラクタ本体内に別の関数を対象オブジェクトのメソッド関数として定義し、そのオブジェクトのメソッド関数が外側の関数本体内の一時変数を参照することです。
これにより、ターゲット オブジェクトが存続期間中常にそのメソッドを維持できる限り、元のコンストラクター本体で使用される一時変数値を間接的に維持できます。最初のコンストラクター呼び出しは終了し、一時変数の名前は消えていますが、変数の値はターゲット オブジェクトのメソッド内で常に参照でき、このメソッドを介してのみ値にアクセスできます。
同じコンストラクターが再度呼び出された場合でも、新しいオブジェクトとメソッドのみが生成され、新しい一時変数は新しい値にのみ対応し、最後の呼び出しとは独立しています。クロージャをより深く理解するために、クロージャの機能と効果をさらに調べてみましょう。
2. クロージャの機能と効果は何ですか?
要するに、クロージャの機能は、a が実行されて返された後、JavaScript のガベージ コレクション メカニズム GC が、a の内部関数 b の実行により占有されているリソースを再利用するのを防ぐことです。 a の変数に依存します。これはクロージャの役割を非常に簡単に説明したものであり、専門的でも厳密でもありませんが、一般的な意味は、クロージャを理解するには段階的なプロセスが必要であるということです。
上記の例では、クロージャの存在により、関数aが戻った後もaのiが常に存在します。このように、c()が実行されるたびに、iは追加後にアラートされるiの値になります。 1.そこで、a が関数 b 以外の値を返す場合、状況はまったく異なります。
a が実行された後、b は a の外に戻されるのではなく、a からのみ参照されるため、関数 a と関数 b は相互に参照します。関数 a と関数 b は外界 (外部参照) によって妨害されないため、GC によってリサイクルされます。 (JavaScript のガベージ コレクションの仕組みについては後で詳しく紹介します)
3. クロージャのミクロの世界
クロージャと関数 a との関係をより深く理解したい場合ネストされた関数 b、他にもいくつかの概念を導入する必要があります。関数実行コンテキスト (実行コンテキスト)、アクティブ オブジェクト (呼び出しオブジェクト)、スコープ (スコープ)、およびスコープ チェーン (スコープ チェーン) です。これらの概念を説明するために、関数 a の定義から実行までのプロセスを例として取り上げます。
1. 関数 a を定義するとき、js インタープリターは関数 a のスコープ チェーンを、a を定義するときに a が存在する「環境」に設定します。 a がグローバル関数の場合、スコープ チェーンはウィンドウ オブジェクトのみになります。
2. 関数 a を実行すると、a は対応する実行コンテキストに入ります。
3. 実行環境を作成するプロセスでは、まず a 、つまり a のスコープにscope属性が追加されます。その値はステップ1のスコープチェーンです。つまり、a.scope=a のスコープ チェーンです。
4. 次に、実行環境が呼び出しオブジェクトを作成します。アクティブ オブジェクトもプロパティを持つオブジェクトですが、プロトタイプを持たないため、JavaScript コードから直接アクセスできません。アクティブ オブジェクトを作成した後、そのアクティブ オブジェクトを のスコープ チェーンの先頭に追加します。この時点で、a のスコープ チェーンには、a のアクティブ オブジェクトとウィンドウ オブジェクトの 2 つのオブジェクトが含まれています。
5. 次のステップでは、関数 a を呼び出すときに渡されるパラメーターを格納する引数属性をアクティブ オブジェクトに追加します。
6. 最後に、関数 a のすべての仮パラメータと内部関数 b への参照を a のアクティブ オブジェクトに追加します。このステップでは関数 b の定義が完了したので、ステップ 3 と同様に、関数 b のスコープチェーンを b が定義されている環境、つまり a のスコープに設定します。
これで関数a全体の定義から実行までが完了しました。このとき、a は関数 b の参照を c に返し、関数 b のスコープ チェーンには関数 a のアクティブ オブジェクトへの参照が含まれます。これは、b が a で定義されたすべての変数と関数にアクセスできることを意味します。関数 b は c によって参照されており、関数 b は関数 a に依存しているため、関数 a は復帰後に GC によってリサイクルされません。
関数bを実行すると上記と同じになります。したがって、実行中の b のスコープ チェーンには、b のアクティブ オブジェクト、a のアクティブ オブジェクト、ウィンドウ オブジェクトの 3 つのオブジェクトが含まれます。関数 b の変数にアクセスするときの検索順序は、
1 になります。存在する場合は返され、存在しない場合は、関数 a のアクティブなオブジェクトが見つかるまで検索を続けます。
2. 関数 b にプロトタイプのプロトタイプ オブジェクトがある場合、関数 b は、自身のアクティブなオブジェクトを検索した後、最初に独自のプロトタイプ オブジェクトを検索し、その後検索を続けます。これは、JavaScript の変数検索メカニズムです。
3. スコープチェーン全体で見つからない場合は、unknown が返されます。
要約すると、この段落では関数の定義と実行という 2 つの重要な単語について説明します。この記事では、関数のスコープは関数の実行時ではなく定義時に決定されると述べています (手順 1 と 3 を参照)。コードの一部を使用して、この問題を説明します。
コードをコピー コードは次のとおりです:

関数 f(x ) {
var g = function () { return x; }
return g;
var h =
alert(); );


このコードの変数 h は、f の無名関数 (g によって返される) を指します。
◆ 関数 h のスコープが、alert(h()) の実行によって決定されると仮定すると、このときの h のスコープチェーンは、 h のアクティブ オブジェクト ->alert のアクティブ オブジェクト -> window オブジェクトになります。
◆ 関数 h のスコープは定義時に決まる、つまり h が指す匿名関数は定義時にスコープが決まるとします。実行中、h のスコープ チェーンは、h のアクティブ オブジェクト -> f のアクティブ オブジェクト -> ウィンドウ オブジェクトになります。
最初の仮定が真の場合、出力値は未定義です。2 番目の仮定が真の場合、出力値は 1 です。 実行結果は 2 番目の仮定が正しいことを証明し、関数のスコープが実際に関数の定義時に決定されることを示しています。
4. クロージャの適用シナリオ
1. 関数内の変数を保護します。最初の例を例にとると、関数 a の i には関数 b によってのみアクセスでき、他の手段ではアクセスできないため、i のセキュリティは保護されます。
2. 変数をメモリ内に保持します。前の例と同様に、クロージャにより、関数 a の i は常にメモリ内に存在するため、c() が実行されるたびに、i は 1 ずつインクリメントされます。
3. 変数のセキュリティを保護して、JS プライベート プロパティとプライベート メソッドを実装します。http://javascript.crockford.com/private.html を参照してください。プライベート プロパティとメソッドにはコンストラクターの外部からアクセスできません:
コードをコピー コードは次のとおりです:

function Constructor(...) {
var that = this
var membername = value;
function membername(...) {...}
}

上記の 3 点はクロージャの最も基本的な適用シナリオであり、多くの古典的なケースはこれらから生じています。
5. Javascript のガベージ コレクション メカニズム
JavaScript では、オブジェクトが参照されなくなった場合、そのオブジェクトは GC によってリサイクルされます。 2 つのオブジェクトが相互に参照し、サードパーティによって参照されなくなった場合、相互に参照している 2 つのオブジェクトもリサイクルされます。関数 a は b によって参照され、b は a の外側の c によって参照されるため、関数 a は実行後にリサイクルされません。
6. 結論
JavaScript クロージャーを理解することは、その解釈と操作メカニズムを理解することによってのみ、より安全で洗練されたコードを作成することができます。
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。