Javascript関数のクローズド詳細解
4355 ワード
多くの本には閉じられていますが、複雑すぎて分かりにくいです.自分で理解してまとめました.
閉包する前に、以下のいくつかの概念を理解する必要があります.
1、実行コンテキスト(execution context)
関数を作成するごとに実行環境を作成します.すなわちコンテキストを実行します.グローバル実行コンテキストはglobal環境であり、関数内部の現在実行環境は現在実行されているコンテキストです. 実行コンテキストは、変数または関数が他のデータにアクセスする権利を定義し、それぞれの行動を決定しました.
2、コンテキストスタックを実行する
活動の実行文脈は論理的にスタックを構成する.スタックの底部は常にグローバルコンテキストであり、上部は現在(アクティブ)の実行文脈である.関数が作成されて呼び出されると、関数の内部で現在の関数がコンテキストを実行してスタックに押し込まれます.もし内部に関数があるならば、スタックの一番上に押し込み続けます.スタックの下には常にグローバル実行コンテキストがあります.
3、変数オブジェクト
各実行コンテキストには、関連する変数オブジェクトがあります.コンテキストで定義されているすべての変数と関数はここにあります.関数であれば、私たちはアクティブオブジェクトと呼びます.変数オブジェクトは、実行コンテキストに関するデータ作用領域であると言えます.実行コンテキストに定義された変数、関数宣言を記憶するための、実行コンテキストに関連する特殊なオブジェクトです.
4、作用ドメインチェーン
作用分域鎖は変数オブジェクトを指すために用いられ、作用域の用途は実行環境にアクセスできるすべての変数と関数に関する規則的なアクセスを保証するものである.スコープの先頭は、常に現在実行されているコードがある環境の変数オブジェクトです. サブオブジェクトは、すべての親のオブジェクトの変数を段階的に上に探します.したがって、親オブジェクトのすべての変数は、子オブジェクトに対しては見えますが、逆は成立しません.
定義:クローズドとは、別の関数のスコープにアクセスできる変数の関数です.ちょっと抽象的すぎじゃないですか?例をあげる
クローズドバッグを使うとよく出る問題点があります.
1、クローズドは関数内の任意の変数を含む最後の値しか取得できません.
ちょっと抽象的なようです.忘れないでください.閉じたパケットは変数オブジェクト全体であり、特殊な変数ではありません.実はここでは引用のように想像できます.
2、thisオブジェクトについて
私たちは、thisオブジェクトが動作時の関数に基づいて環境バインディングを実行していることを知っています.グローバル関数では、thisはwindowに等しいです.関数があるオブジェクトとしての方法で呼び出すと、thisはそのオブジェクトに等しいです.しかし、匿名関数の実行環境は大域的であるため、そのthisオブジェクトは通常windowを指す.第1ステップは、取得したfirstが戻る匿名関数であり、このときのget NameFunは、Objectの方法として呼び出され、getNameFun()にthisが使用されると、このときのthisは、Objectオブジェクトを指す. の第二のステップは、first関数を呼び出して、このときfirst関数を呼び出したが、first関数はオブジェクト内で呼び出されなかったので、関数として呼び出されたのは、グローバルスコープであるので、first関数のthisはwindowを指していることがよく分かります.なぜ匿名関数は、スコープ(外部スコープ)を含むthisオブジェクトを取得していないのですか? 各関数が呼び出された時、そのオブジェクトは自動的に二つの特殊変数を取得します.内部関数は、この2つの変数を検索すると、そのアクティブなオブジェクトだけが検索されますので、外部関数の2つの変数に直接アクセスすることはできません.外部作用変数のthisはどうやって得られますか?外部作用領域のthisオブジェクトを一つのクローズドにアクセスできる変数に保存すると、クローズドがそのオブジェクトにアクセスできます.
閉包用途まとめ
1、関数内部の変数を読み取り、関数内部と外部の橋梁を構築することができます.2、いくつかの変数の値を常にメモリに保持させます.
クローズドを使う注意点
1)クローズドは関数の変数がメモリに保存されるため、メモリの消耗が大きいので、クローズドを濫用してはいけません.そうでないと、ウェブページの性能問題が発生し、IEでメモリのリークを引き起こす可能性があります.解決方法は、関数を終了する前に使用しないローカル変数をすべて削除します.2)親関数の外部で、親関数の内部変数の値を変更します.したがって、親関数を対象として使用する場合は、クローズドをそのパブリックメソッドとして、内部変数をそのプライベート属性として扱い、親関数内部変数の値を勝手に変えないように注意してください.
「JavaScript高等プログラム設計第3版」
閉包する前に、以下のいくつかの概念を理解する必要があります.
1、実行コンテキスト(execution context)
関数を作成するごとに実行環境を作成します.すなわちコンテキストを実行します.グローバル実行コンテキストはglobal環境であり、関数内部の現在実行環境は現在実行されているコンテキストです. 実行コンテキストは、変数または関数が他のデータにアクセスする権利を定義し、それぞれの行動を決定しました.
2、コンテキストスタックを実行する
活動の実行文脈は論理的にスタックを構成する.スタックの底部は常にグローバルコンテキストであり、上部は現在(アクティブ)の実行文脈である.関数が作成されて呼び出されると、関数の内部で現在の関数がコンテキストを実行してスタックに押し込まれます.もし内部に関数があるならば、スタックの一番上に押し込み続けます.スタックの下には常にグローバル実行コンテキストがあります.
3、変数オブジェクト
各実行コンテキストには、関連する変数オブジェクトがあります.コンテキストで定義されているすべての変数と関数はここにあります.関数であれば、私たちはアクティブオブジェクトと呼びます.変数オブジェクトは、実行コンテキストに関するデータ作用領域であると言えます.実行コンテキストに定義された変数、関数宣言を記憶するための、実行コンテキストに関連する特殊なオブジェクトです.
4、作用ドメインチェーン
作用分域鎖は変数オブジェクトを指すために用いられ、作用域の用途は実行環境にアクセスできるすべての変数と関数に関する規則的なアクセスを保証するものである.スコープの先頭は、常に現在実行されているコードがある環境の変数オブジェクトです. サブオブジェクトは、すべての親のオブジェクトの変数を段階的に上に探します.したがって、親オブジェクトのすべての変数は、子オブジェクトに対しては見えますが、逆は成立しません.
var f1 = function() {
function f2() {
function f3() {}
}
}
//f3 f3 -> f2 -> f1 -> global
閉め切ってもいいですよ.定義:クローズドとは、別の関数のスコープにアクセスできる変数の関数です.ちょっと抽象的すぎじゃないですか?例をあげる
var outter = function() {
var a = 1;
function inner() {
return a;
}
return inner; //
}
var result = outter(); //
console.log(result()); //1
JavaScriptの作用ドメインチェーンの特性から、関数の中で外部の変数にアクセスできますが、逆にだめです.しかし、上記の例ができました.これは閉包です.innerがoutter中の局所変数を読み取ることができるなら、innerをリターン値として、outterの外部で内部変数を読み取ることができるじゃないですか?前のコードのinner関数は、クローズドです.各種の専門文献の「クローズド」の定義はとても抽象的で、分かりにくいです.私の理解では、クローズドとは他の関数の内部変数を読み取ることができる関数です.Javascript言語では、関数内部のサブ関数だけが局所変数を読み取ることができるので、クローズドを単に「関数の内部に定義された関数」と理解することができます.したがって、本質的には、クローズドとは、関数の内部と関数の外部をつなぐ橋のことである.クローズドバッグを使うとよく出る問題点があります.
1、クローズドは関数内の任意の変数を含む最後の値しか取得できません.
ちょっと抽象的なようです.忘れないでください.閉じたパケットは変数オブジェクト全体であり、特殊な変数ではありません.実はここでは引用のように想像できます.
function createArray() {
var result = new Array();
for(var i = 0;i<10;i++) {
result[i] = function() {
return i;
};
}
return result;
}
var r = createArray();
console.log(r);
for(var i=0;i<10;++i)
console.log(r[i]()); //10 10
その理由は、変数オブジェクト全体がクローズドに保存されているため、各関数に同じ変数オブジェクトが保存されています.それらは同じ変数iを参照します.したがって、クローズドを実行するとき、iは10まで実行されており、戻るiは自然と10である.2、thisオブジェクトについて
私たちは、thisオブジェクトが動作時の関数に基づいて環境バインディングを実行していることを知っています.グローバル関数では、thisはwindowに等しいです.関数があるオブジェクトとしての方法で呼び出すと、thisはそのオブジェクトに等しいです.しかし、匿名関数の実行環境は大域的であるため、そのthisオブジェクトは通常windowを指す.
var name = "The Window";
var object = {
name: "My object",
getNameFunc: function() {
return function() {
return this.name;
};
}
}
console.log(object.getNameFunc()()); //The Window
どうして最後の結果は「Objectの中のname"My object」ではなく「The Window」ですか? まず、関数としての関数呼び出しと関数を理解することが方法として呼び出されます.最後の文を二つのステップに分けて実行します.var first = object.getNameFunc();
var second = first
そのうちvar name = "The Window";
var object = {
name: "My object",
getNameFunc: function() {
var name = 19;
var that = this;
return function() {
return that.name;
};
}
}
console.log(object.getNameFunc()()); //My object
このとき呼び出します.getNameFun実行時の活動変数は何がありますか?name that function.匿名関数を実行すると、getNameFun()のアクティブオブジェクトを同時に参照するので、thatとageの値を取得することができます.しかし、グローバル環境で呼び出された匿名関数なので、匿名関数内部のthisは、やはりwindowを指す.閉包用途まとめ
1、関数内部の変数を読み取り、関数内部と外部の橋梁を構築することができます.2、いくつかの変数の値を常にメモリに保持させます.
クローズドを使う注意点
1)クローズドは関数の変数がメモリに保存されるため、メモリの消耗が大きいので、クローズドを濫用してはいけません.そうでないと、ウェブページの性能問題が発生し、IEでメモリのリークを引き起こす可能性があります.解決方法は、関数を終了する前に使用しないローカル変数をすべて削除します.2)親関数の外部で、親関数の内部変数の値を変更します.したがって、親関数を対象として使用する場合は、クローズドをそのパブリックメソッドとして、内部変数をそのプライベート属性として扱い、親関数内部変数の値を勝手に変えないように注意してください.
「JavaScript高等プログラム設計第3版」