javascriptの中のクローズド


http://www.knowsky.com/442121.html
Javascriptのクローズドを深く理解する
最近はネットでJavascriptのクローズドに関する資料をたくさん調べましたが、書いているのは非常な学術と専門です.初心者にとっては、クローズドの理解はおろか、テキストの説明さえも分かりにくいです.この文を書く目的は最も通俗的な文字でJavascriptの閉じている正体を明らかにすることです.
一、クローズドとは何ですか?
「公式」の解釈は、多くの変数と結合された環境を持つ表現(通常は関数)を意味し、これらの変数も表現の一部です.
この言葉を直接読む人は少ないと思います.彼の説明はあまりにも学術的なものですから.どのようにJavascriptでクローズドを作成するかを教えたいです.なぜなら、クローズドの作成過程をスキップして、クローズドの定義を直接理解するのはとても難しいです.下のコードを見てください.
function a(){
 var i=0;
 function b(){
 alert(++i);
 }
 return b;
}
var c = a();
c();
このコードには二つの特徴があります.
1、関数bが関数aの内部にネストされている.
2、関数aは関数bを返します.
このように、var c=a()を実行した後で、変数cは実際に関数bを指して、c()を実行した後に1つのウィンドウを弾いてiの値を表示します(初めては1です).このコードは実は一つのクローズドを作成しました.なぜですか?関数a以外の変数cは関数a内の関数bを参照しているからです.
関数aの内部関数bが関数a以外の変数によって参照されると、クローズドパケットが作成されます.
あなたはきっとまだクローズドを理解していないと思います.クローズドが何の効果があるか分かりませんので、引き続き探してみます.
二、カバンを閉じて何の効果がありますか?
簡単に言えば、クローズドの役割は、aが実行されてから戻ってきた後、クローズドはJavascriptのゴミ回収メカニズムGCがaによって占有された資源を回収しないようにします.aの内部関数bの実行はaの変数に依存します.これは閉包作用に対する非常にはっきりした説明で、専門でもないし、厳格でもないが、大体の意味はこのようにして、閉包を理解するには順序を追って漸進する過程が必要である.
上記の例では、関数aが戻ると、aのiは常に存在するので、c()を実行する毎に、iはプラス1の後、alertからiの値を出す.
aが関数bでない場合は、別の状況を想像します.aが実行された後、bはaの外界に戻されず、aに引用されただけで、この時aもbに引用されるだけで、関数aとbは相互に参照しても外界に邪魔されず、関数aとbはGCに回収される.(Javascriptのゴミ回収メカニズムについては後述する)
三、クローズドのミクロの世界
クローズド及び関数aとネスト関数bとの関係をより深く理解するためには、関数の実行環境、アクティブオブジェクト、スコープ、スコープチェーンの他のいくつかの概念を導入する必要があります.これらの概念は、関数aが定義から実行までのプロセスを例に挙げて説明される.
1、関数aを定義すると、js解釈器は関数aの作用ドメインチェーンを定義aに設定します.aがグローバル関数であるなら、scope chainにはwindowオブジェクトしかありません.
2、関数aが実行されると、aは相応の実行環境に入る.
3、実行環境を作成する過程で、まずaにscope属性、つまりaの作用領域を追加します.その値は第1ステップのscope chainです.a.scope=aの作用ドメインチェーンです.
4、そして実行環境は活動対象を作成します.オブジェクトも属性を持つオブジェクトですが、プロトタイプがなく、JavaScriptコードで直接アクセスできません.アクティブなオブジェクトを作成したら、アクティブなオブジェクトをaのアクティブなドメインチェーンの一番上に追加します.この時、aの作用領域チェーンは2つのオブジェクトを含んでいます.aの活動対象とwindowオブジェクトです.
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のスコープには3つのオブジェクトが含まれています.bの活動対象、aの活動対象、windowオブジェクトは、下図のようになります.
図に示すように、関数bで変数にアクセスすると、検索順序は先に自身の活動オブジェクトを検索し、存在しない場合は戻ります.検索関数aの活動オブジェクトが存在しない場合は、検索を継続して、検索します.スコープ全体が見つからない場合、undefinedに戻ります.プロトタイプのオブジェクトが関数bに存在する場合は、自身のオブジェクトを検索した後、プロトタイプのオブジェクトを探してから検索します.これはJavascriptの変数検索の仕組みです.
四、クローズドの応用シーン
1、保護関数内の変数の安全.最初の例では、関数aのiは関数bのみでアクセスでき、他の経路でアクセスできないので、iのセキュリティが保護されている.
2、メモリ内で変数を維持します.前の例のように、関数a中iはメモリに存在しているので、c()を実行するたびに、iに1を加算します.
以上の2点は閉包の最も基本的な応用シーンであり、多くの古典的なケースはここから由来しています.
五、Javascriptのゴミ回収メカニズム
Javascriptでは、オブジェクトがもう引用されないと、このオブジェクトはGCによって回収されます.2つのオブジェクトが相互に参照され、第三者から引用されなくなると、この2つの相互参照の対象も回収されます.関数aはbによって引用され、bはa以外のcによって引用されるので、これは関数aが実行されても回収されない理由です.