JS階段シリーズのクローズド
3436 ワード
クローズドとは、他の関数の内部変数を読み取る関数であり、クローズドを単に「関数の内部に定義された関数」として理解することができます.
阮一峰のブログを読んで閉包について説明した後、自分も閉包に対して一定の認識ができました.まず閉包を理解する前に、JavaScriptの特殊な変数の作用領域を理解しなければなりません.変数のスコープには2つの大域変数と局所変数があります.
この本を読んでいるうちに、二つのパッケージ関連の例プログラムが見つかりました.一つ目は次の通りです.
なぜ匿名関数は、スコープ(外部スコープ)を含むthisオブジェクトを取得していないのですか?各関数が呼び出されると、そのオブジェクトは自動的に二つの特殊な変数を取得します.内部関数は、この2つの変数を検索すると、そのアクティブなオブジェクトだけが検索されますので、外部関数の2つの変数に直接アクセスすることはできません.——<>
次のコードを見てください.
阮一峰のブログを読んで閉包について説明した後、自分も閉包に対して一定の認識ができました.まず閉包を理解する前に、JavaScriptの特殊な変数の作用領域を理解しなければなりません.変数のスコープには2つの大域変数と局所変数があります.
var n = 999;
function f1(){
alert(n);
}
f1();//999
以上のコードからJavascript言語の特殊な点が分かります.関数の内部で直接大域変数を読み取ることができます.もちろん、関数の外部では当然、関数内部の局所変数を読み取ることができません.外部から内部の局所変数を読み取るにはどうすればいいですか?関数の内部に関数を定義すると、次のようになります.function f1(){
var n = 999;
function f2(){
alert(n);//999
}
}
上記のコードでは、関数f2
が関数f1
に含まれているので、関数f2
はf1
の中の局所変数にアクセスできます.関数f2
を戻り値とすると、外部で内部の局所変数を読み取ることができます.コードは以下の通りです.function f1(){
var n = 999;
function f2(){
alert(n);//999
}
return f2;
}
var result = f1();
result(); //999
実際には上のコードでは、関数f2
はクローズドされています.この中では、クローズドされている二つの役割について言及します.最初は関数内部の変数、つまり上記のコードの役割です.二つ目はこれらの変数の値を常にメモリに保持させ、次のコードを見れば第二の役割が理解できるという意味です.function f1(){
var n=999;
nAdd=function(){n+=1}
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000
関数f2
は、大域変数result
に値を与えているので、関数f2
はメモリに保存され、関数f2
の親関数はf1
で、f1
に依存しているので、f1
もメモリに保存され、f1
の中の変数もメモリに保存され、回収されない.この本を読んでいるうちに、二つのパッケージ関連の例プログラムが見つかりました.一つ目は次の通りです.
function createFunctions(){
var result = new Array();
for(var i = 0; i < 10; i++) {
result[i] = function(){
return i;
};
}
return result;
}
正常に戻った結果は、それぞれの関数が自分のインデックス値を返しますが、最終的な結果は、各関数が10を返します.これは、各関数の作用領域チェーンにcreateFunctions()
関数のアクティブオブジェクトが保存されているため、それらが参照するのは同じ変数iであり、createFunctions()
関数が戻り、iの値が10になると、各関数は変数iを保存する同じ変数オブジェクトを参照している.次のように、別の匿名関数を作成することにより、強制的に閉じられた動作を予想通りにすることができます.function createFunctions(){
var result = new Array();
for(var i = 0; i < 10; i++) {
result[i] = function(num){
return function(){
return num;
}
}(i);
}
return result;
}
二つ目は:var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()());
上のコードが返した結果は、「My Object」ではなく「The Window」です.私たちはこれを理解する前に、方法の呼び出しと関数の呼び出しの違いを理解します.最後の言葉を二つの言葉に分解します.var first = object.getNameFunc();
var result = first();
第1の文で呼び出されたのはobject
のgetNameFunc()
の方法であったので、this
のオブジェクトはobject
であったが、第2の文ではfirst()
は関数呼出に属し、グローバル環境で呼び出されたのでthis
はwindow
になった.なぜ匿名関数は、スコープ(外部スコープ)を含むthisオブジェクトを取得していないのですか?各関数が呼び出されると、そのオブジェクトは自動的に二つの特殊な変数を取得します.内部関数は、この2つの変数を検索すると、そのアクティブなオブジェクトだけが検索されますので、外部関数の2つの変数に直接アクセスすることはできません.——<>
次のコードを見てください.
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;// getNameFunc() this that
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); //"My Object"
戻ってきた結果は、外部作用領域のthisをクローズドパケットでアクセスできる変数に保存できるので、期待される「My Object」です.