閉鎖はJavaScriptの重要な機能であり、それらの最大の機能は、機能操作中に情報を保存することです。 JavaScriptでは、閉鎖の多くの機能は、関数呼び出し中のスコープチェーンから派生しています。
スコープチェーンのチェーンは、オブジェクトと変数を呼び出します
JavaScriptの各関数呼び出しについて、JavaScriptはローカルオブジェクトを作成して、関数に定義されたローカル変数を保存します。関数内にネストされた関数がある場合、JavaScriptは、既に定義されているローカルオブジェクトにネストされたローカルオブジェクトを定義します。関数の場合、ネストされた関数定義のレイヤーがあります。このローカルオブジェクトは、ecmascript 3の「function callオブジェクト」(「コールオブジェクト」と呼ばれ、ecmascript 5の「宣言的環境記録」と改名されましたが、個人的にはecmascript 3の名前は理解しやすいと思います)。次の関数呼び出しは、例として使用されます。
コードコピーは次のとおりです。
関数f(x){
var a = 10;
*xを返します;
}
console.log(f(6)); // 60
この単純な例では、f()関数が呼び出されると、javaScriptはf()関数の呼び出しオブジェクトを作成します(f_invokeobjと呼びましょう)。 f_invokeobjオブジェクト内には2つのプロパティがあります。aとx。 f()が実行されると、A値は10、x値は6であるため、最終的な返品結果は60です。図は次のとおりです。
機能のネストがある場合、JavaScriptは複数の関数呼び出しオブジェクトを作成します。
コードコピーは次のとおりです。
関数f(x){
var a = 10;
a*g(x)を返します。
関数G(b){
b*bを返します。
}
}
console.log(f(6)); // 360
この例では、f()関数を呼び出すと、JavaScriptは2つの属性aとx、値aは10、値xは6です。 f()を実行すると、javaScriptはf()関数のg()関数を解析および定義し、属性Bを持つg()(g_invokeobj)の呼び出しオブジェクトを作成し、値bは渡されたパラメーターxと同じであるため、最終的な返品結果は360です。
ご覧のとおり、関数呼び出しオブジェクトはチェーンを形成します。埋め込まれた関数g()が実行され、変数値を取得する必要がある場合、最新の関数呼び出しオブジェクトから検索を開始します。検索できない場合は、Function Call Objectチェーンに沿ってさらにコールオブジェクトを検索します。これは、いわゆる「変数のスコープチェーン」です。同じ変数が2つの関数呼び出しオブジェクトに表示される場合、関数はそれに最も近いコールオブジェクトの変数値を取得します。
コードコピーは次のとおりです。
関数f(x){
var a = 10;
a*g(x)を返します。
関数G(b){
var a = 1;
b*b*aを返します。
}
}
console.log(f(6)); // 360、3600ではありません
上記の例では、変数Aは、g()関数の呼び出しオブジェクト(g_invokeobj)とf()関数の呼び出しオブジェクト(f_invokeobj)に異なる値を持っています。 g()関数を実行する場合、g()関数内で使用されるaの値は1であり、g()関数の外側で使用される値は1です。この時点での関数呼び出しオブジェクトチェーンは次のとおりです。
閉鎖とは何ですか?
JavaScriptのすべての関数はオブジェクトであり、関数を定義する場合、対応する関数呼び出しオブジェクトが生成されます。関数定義は、一連の関数を呼び出すオブジェクトに対応します。関数オブジェクトが存在する限り、対応する関数呼び出しオブジェクトが存在します。関数が使用されなくなると、対応する関数呼び出しオブジェクトはゴミ収集されます。また、関数オブジェクトと関数チェーンコールオブジェクトのこの組み合わせは、「クロージャー」と呼ばれます。 f()関数とg()関数の上記の例では、2つの閉鎖があります。f()関数オブジェクトとf_invokeobjオブジェクトは閉鎖を形成し、g()関数オブジェクトとg_invokeobj-f_invokeobjオブジェクトチェーンが2回目の閉鎖を形成します。 G()関数が使用されなくなったため、g()関数が実行されると、g()閉鎖はガベージが収集されます。次に、f()関数が実行されると、同じ理由でf()閉鎖もゴミが収集されます。
閉鎖の定義から、結論を描くことができます。すべての関数はオブジェクトであり、すべての関数が実行後に対応するコールオブジェクトチェーンもあるため、定義後の閉鎖です。
ただし、閉鎖を実際に機能させるのは、ネストされた機能の場合です。埋め込み関数は外部関数が実行されているときにのみ定義されるため、埋め込み関数(特に外部関数のローカル変数値)に格納されている変数値は、この実行中の値です。埋め込まれた関数オブジェクトがまだ存在する限り、その閉鎖は依然として存在します(閉鎖の変動値は変化しません)したがって、関数実行プロセスの情報を保存する目的を達成します。次の例を考えてみましょう。
コードコピーは次のとおりです。
var a = "外部";
関数f(){
var a = "inside";
function g(){return a;}
gを返します。
}
var result = f();
console.log(result()); //内部
この例では、f()関数が実行されると、g()関数が定義され、g()関数の閉鎖が作成されます。 G()閉鎖にはG_INVOKEOBJ-F_INVOKEOBJオブジェクトチェーンが含まれるため、F()関数の実行中の変数Aの値が保存されます。 console.log()ステートメントが実行されると、g関数オブジェクトが存在するため、g()閉鎖が依然として存在します。このまだ存在するG関数オブジェクトを実行すると、JavaScriptはまだ存在するg()閉鎖を使用し、そこから変数a( "内部")の値を取得します。