【閉包】JSの閉包とは何か
8441 ワード
JSの中の閉包は見ていると難しくないようだが、またぼんやりしやすいもので、多くの人が私と同じように知っていると信じている.今回は最も実用的な角度からこの問題を研究してみよう.
1.クローズって何?
MDNによる定義:
関数とその周囲の状態(lexical environment,文法環境)への参照が結合されて閉パケット(closure)を構成します.つまり、閉パケットは内部関数から外部関数の役割ドメインにアクセスして、ここの文法環境を説明することができます.つまり、私たちがよく言っているコンテキストを指します.例を見てみましょう
displayNameという関数の内部にはname変数はありませんが、その構文環境、すなわち外部関数initの内部にname変数があるため、displayNameでこの変数を使用することができます.これは、関数displayNameに文法環境への参照があるからです.この参照がないgetNameではname変数は使用できません.
2つ目の例を見てみましょう.閉包は関数によって行われます.
上記の例とは異なり、このmakeFunc関数の戻り値は、まだ実行されていない関数です.myFuncを実行するとnameの値が正常に印刷されます.これは、displayNameという関数がmakeFuncという環境の変数nameを外部に持ち込み、displayNameに自分の構文環境への参照が含まれていることをさらに証明します.
まとめてみると、
関数Aの内部には関数Bがあり、関数BにはAの内部環境への参照があるため、BではBの作成時にAのすべての変数にアクセスでき、関数Aの外部ではAの変数にアクセスできない.AにおいてBを戻り値とすると、返される関数Bおよび関数BにおけるA内部環境への参照が閉パケットとなる
2.カバンを閉じて何をする
上記の定義により,この問題に答えることができ,閉パケットの存在は関数にその外部関数の変数を使用させることができる.
でも、何の役にも立たないようです.では、閉鎖にはどんな実際の価値があるのでしょうか.
Javaのような従来のオブジェクト向け言語では、クラスには独自のプライベートメンバーがあり、外部からアクセスできないが、JSではクラスをclassで定義したり、関数を構築してオブジェクトを定義したりしても、プライベート変数の説明はなく、パッケージを閉じることでプライベート変数の定義を完了できるメカニズムは存在しないことを知っています.
もう1つの例を見てみましょう.
この方法によりプライベート変数が実現され,外部ではNumのnumメンバーにアクセスできず,予約された関数インタフェースでのみ操作とアクセスが可能であることが分かった.
したがって、データの隠しやカプセル化が必要な場所では、閉パッケージを使用することができます.
注意:
前述したように,内部関数における参照は,指向するときにその関数を作成する際の文法環境,すなわち,後でこの文法環境が変化すると,この参照が指向する内容が直感と一致しない.したがって、閉パッケージでは、その後に変化するすべての変数を使用しないでください.ループ変数など、最も一般的なものです.閉パッケージはパフォーマンスに悪影響を及ぼします.必要でなければ、使用しないでください.
1.クローズって何?
MDNによる定義:
関数とその周囲の状態(lexical environment,文法環境)への参照が結合されて閉パケット(closure)を構成します.つまり、閉パケットは内部関数から外部関数の役割ドメインにアクセスして、ここの文法環境を説明することができます.つまり、私たちがよく言っているコンテキストを指します.例を見てみましょう
function init() {
var name = "Mozilla"; // name init
function displayName() { // displayName() ,
alert(name); //
}
displayName();
}
function getName(){
console.log(name);
}
init()//alert("Mozilla")
getName()//name is not defined
displayNameという関数の内部にはname変数はありませんが、その構文環境、すなわち外部関数initの内部にname変数があるため、displayNameでこの変数を使用することができます.これは、関数displayNameに文法環境への参照があるからです.この参照がないgetNameではname変数は使用できません.
2つ目の例を見てみましょう.閉包は関数によって行われます.
function makeFunc() {
var name = "Mozilla";
function displayName() {
console.log(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
上記の例とは異なり、このmakeFunc関数の戻り値は、まだ実行されていない関数です.myFuncを実行するとnameの値が正常に印刷されます.これは、displayNameという関数がmakeFuncという環境の変数nameを外部に持ち込み、displayNameに自分の構文環境への参照が含まれていることをさらに証明します.
まとめてみると、
関数Aの内部には関数Bがあり、関数BにはAの内部環境への参照があるため、BではBの作成時にAのすべての変数にアクセスでき、関数Aの外部ではAの変数にアクセスできない.AにおいてBを戻り値とすると、返される関数Bおよび関数BにおけるA内部環境への参照が閉パケットとなる
2.カバンを閉じて何をする
上記の定義により,この問題に答えることができ,閉パケットの存在は関数にその外部関数の変数を使用させることができる.
でも、何の役にも立たないようです.では、閉鎖にはどんな実際の価値があるのでしょうか.
Javaのような従来のオブジェクト向け言語では、クラスには独自のプライベートメンバーがあり、外部からアクセスできないが、JSではクラスをclassで定義したり、関数を構築してオブジェクトを定義したりしても、プライベート変数の説明はなく、パッケージを閉じることでプライベート変数の定義を完了できるメカニズムは存在しないことを知っています.
もう1つの例を見てみましょう.
function number(){
var num=0;
function add(){
num++;
}
function dec(){
num--;
}
function val(){
return num;
}
return{
add:add,
dec:dec,
val:val
}
}
var Num=number();
console.log(Num.num);//undefined
Num.val();//0
Num.add();
Num.val();//1
Num.dec();
Num.val()//0
この方法によりプライベート変数が実現され,外部ではNumのnumメンバーにアクセスできず,予約された関数インタフェースでのみ操作とアクセスが可能であることが分かった.
したがって、データの隠しやカプセル化が必要な場所では、閉パッケージを使用することができます.
注意:
前述したように,内部関数における参照は,指向するときにその関数を作成する際の文法環境,すなわち,後でこの文法環境が変化すると,この参照が指向する内容が直感と一致しない.したがって、閉パッケージでは、その後に変化するすべての変数を使用しないでください.ループ変数など、最も一般的なものです.閉パッケージはパフォーマンスに悪影響を及ぼします.必要でなければ、使用しないでください.