javascript核心知識整理の一つ:関数は閉じます.

7076 ワード

オブジェクトを呼び出す
javascript解釈器が関数を呼び出すと、まず機能領域を関数を定義するときに機能するその作用領域チェーンが設定されます.次に、スコープの前に新しいオブジェクトを追加します.これを呼び出しオブジェクトといいます.呼び出し対象はアルグメンントという属性で初期化され、この属性は関数のアーグメンントオブジェクトを参照しています.関数の名前のパラメータを呼び出しオブジェクトの後ろに追加します.var文で宣言した任意の局所変数もこのオブジェクトに定義されています.この呼び出しオブジェクトは、スコープの前端に位置する以上、局所変数、関数パラメータ、およびAgmentsオブジェクトは、関数内のスコープ内にある.もちろん、これはまた、ドメインチェーンのより上位層に作用する同名の属性を隠すことを意味する.
関数のスコープとクローズド
語法の作用領域:javascriptの関数は語法によって作用域を区分するもので、作用域を動的に区分するものではない.これは、それらがそれらの作用領域を実行するのではなく、それらを定義する役割領域で行うことを意味する.関数を定義すると,現在の作用分域鎖は保存され,関数の内部状態の一部となる.トップクラスでは、スコープチェーンはグローバルオブジェクトだけで構成され、スコープとは関係がない.しかし、ネストされた関数を定義すると、ロールドメインチェーンは周辺の含有関数を含む.これはネストされた関数が関数を含むすべてのパラメータと局所変数にアクセスできることを意味する.作用分域鎖は関数が定義されると固定されますが、作用分域鎖で定義された属性はまだ固定されていません.スコープチェーンは「アクティブ」であり、関数は呼び出し時に任意の現在のバインディングにアクセスできます.
クローズドの埋め込み関数として
javascriptは埋め込まれた関数を許可して、関数をデータとして使用することができます.そして、詞法の作用領域を使って、これらの要素が相互作用して、驚くべき効果と強力な効果を作り出しました.この点を用いると、関数fに定義された関数gが考えられる.fが呼び出されると、このフィールドチェーンはfに対するコールの対象を含み、後はグローバルオブジェクトである.gはfで定義されているので、この作用分域チェーンはgの定義の一部として保存されている.gが呼び出されると、ロールフィールドチェーンには3つのオブジェクトが含まれています.自分の呼び出しオブジェクト、fの呼び出しオブジェクト、およびグローバルオブジェクトです.埋め込み関数が定義された同じ語法のスコープで呼び出されるとよく分かります.下記のようにコードには驚くべきものはありません.
var x = "golbal";
function f(){
var x = "local";
function g() { alert(x); }
g();
}
f(); //Calling this function displays "local"
しかし、javascriptでは、関数は他の値と同じであり、データでもあるので、それらは関数から返してもいいです.それらは関数から返してもいいです.オブジェクト属性に割り当てられて、行列に保存されています.埋め込みの関数に関係しない限り、これは驚くべきことではない.下記のコードを考慮して、関数が含まれています.入れ子の関数を返します.この関数を呼び出すたびに、関数を返します.戻ってくる関数のjavascriptコードはいつも同じですが、外周関数のパラメータ値は呼出ごとに異なるため、作成されたスコープは少し違っています.戻ってきた関数を中国の配列に格納し、それらの各々を呼び出します.毎回異なる値を返します.各関数は同じjavascriptコードを含み、各セグメントのコードは同じスコープから呼び出されるので、異なるリターンの要素は関数定義が存在するスコープである可能性があります.
//This function returns a function each time it is called
//
The scope in which the function is defined differs for each call
function makefunc(x){
return function(){return x;}
}

//Call makefunc() several times,and save the results in an array;
var a = {makefunc(0),makefunc(1),makefunc(2)};

//Now call these functions and display their values.
//
Although the body of each function is the same,the scope is different,
//and each call returns a different value:

alert(a[0]());//displays 0
alert(a[1]());//displays 1
alert(a[2]());//displays 2
このコードの結果は,この法の作用領域規則を厳格に適用することから期待されるものであり,関数はその定義された作用領域で実行される.しかし,これらの結果は驚くべき原因として,局所作用領域を定義した関数が脱退すると,局所作用領域が終端し,退出することが期待されるからである.つまり、実際にはこれが通常発生している状況です.関数が呼び出されると、呼び出し対象を作成して、スコープに配置します.関数が終了すると、コール対象もスコープから削除されます.ネストの関数が関与していない場合、スコープチェーンは呼び出し対象に対する唯一の参照です.チェーンからオブジェクトが除去されると、それに対する参照がなくなり、最終的にはそのごみを収集することによって完成されます.
しかし,ネストの関数はこの情景を変えた.ネストされた関数が作成された場合、この関数の定義は呼び出し対象を参照します.この関数で定義されている作用ドメインチェーンの先端にオブジェクトを呼び出します.しかし、ネストされた関数が外周関数の内部でのみ使用される場合、ネスト関数に対する唯一の参照は呼び出し対象にある.外周関数が戻ると、入れ子の関数は呼び出し対象を引用し、対象を呼び出して入れ子の関数を参照しましたが、他のものは彼ら2つを引用していませんので、これらの2つのオブジェクトはすべてゴミ収集ができます.
ネストされた関数の参照をグローバルスコープに保存すると、また違ってきます.外周関数の戻り値として入れ子の関数を使用するか、入れ子の関数を他のオブジェクトの属性として記憶します.この場合、ネストの関数の外部参照があり、ネストの関数は、その参照を周辺関数の呼び出しオブジェクトに保持します.その結果、外周関数の特定の呼び出しの対象は依然として存在し、関数のパラメータと局所変数の名前と値はこのオブジェクトで維持される.javascriptコードはコールオブジェクトに直接アクセスしないが、彼が定義している属性は埋め込み関数の任意の呼び出しのためのスコープチェーンの一部である.(ただし、外周関数が二つのネスト関数の大域参照を記憶している場合、この二つの埋め込み関数は同一の呼び出し対象を共有し、一つの関数の一回の呼び出しによって変化したものは他の関数の呼び出しにも見られます.)javascript関数の場合は実行するコードとともに、これらのコードを実行する作用領域からなる複合体です.コンピュータ科学用語では、このコードとスコープの複合体をクローズドといいます.
以上の文字は「javascript権威の手引き」に出ていますが、読みづらいです.ちょっと分かりやすい言葉で説明します.
匿名関数の最も興味深い用途は、クローズド・パケットを作成することである.クローズド(closure)は、埋め込み関数によって生成される保護された変数空間である.javascriptは関数級のスコープを持っています.これは関数の内部に定義された変数が関数の外部にアクセスできないことを意味します.javascriptの作用域はまた語法の性質のです.これは、関数が呼び出しの役割領域ではなく、その役割領域を定義する中で動作することを意味する.この二つの要素を結合すると、変数を匿名関数にくるむことで保護することができます.以下の二つのコードを見てください.出力は同じです.
var f = (function(){ 
var id = 0;
return function(){return id++;};
})();

document.write(f());//display 0
document.write(f());//display 1
document.write(f());//display 2
document.write(f());//display 3
document.write(f());//display 4

var f;
(function(){
var id = 0;
f = function(){return id++;};
})();

document.write(f());//display 0
document.write(f());//display 1
document.write(f());//display 2
document.write(f());//display 3
document.write(f());//display 4