状態関数とその周辺(字句環境、字句環境参照)が一緒にバンドルされている(または関数が参照で囲まれている)場合、そのような組み合わせがクロージャー(クロージャー)です。つまり、クロージャーを使用すると、内部関数の外部関数のスコープにアクセスできます。JavaScriptでは、関数が作成されるたびに、関数の作成と同時にクロージャが作成されます。
function foo() {
var i = 0;
return function(){
i++;
console.log(i);
};
}
const bar = foo();
const bar2 = foo();
bar(); //1
bar(); //2
bar2() //1
bar2() //2
bar() // 3
bar2() // 3
字句スコープ
次のコードを見てください。
function init() {
var name = "Mozilla"; // name 是一个被 init 创建的局部变量
function displayName() { // displayName() 是内部函数,一个闭包
alert(name); // 使用了父函数中声明的变量
}
displayName();
}
init();
init()
ローカル変数name
とdisplayName()
。という名前の関数を作成し ました 。displayName()
これはで定義されinit()
た内部関数で あり、init()
関数本体でのみ使用できます 。displayName()
独自のローカル変数はないことに注意してください。ただし、外部関数の変数にアクセス displayName()
できるためinit()
、親関数で宣言された変数 を使用できます name
。
このJSFiddleリンクを使用してコードを実行した後 、displayName()
関数alert()
内のステートメントがname
変数の値を正常に表示し ている ことがわかりました (変数はその親関数で宣言されています)。この字句スコープの例では、ネストされた関数の場合にパーサーが変数名を解決する方法について説明します。字句という用語は、ソースコードで変数が宣言されている場所に基づいて、字句スコープが変数を使用できる場所を決定するという事実を指します。ネストされた関数は、外部スコープで宣言された変数にアクセスできます。
閉鎖
次の例を考えてみましょう。
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
このコードを実行した場合の効果はinit()
、前の関数の例と まったく同じです。違い(そして興味深い)は、内部 関数がdisplayName()
実行前に外部関数から戻ることです。
一見すると、このコードが正常に実行できることを確認するのは直感的ではないかもしれません。一部のプログラミング言語では、関数内のローカル変数は関数の実行中にのみ存在します。いったん makeFunc()
実行が完了すると、あなたはと思うかもしれ name
変数にアクセスできなくなります。ただし、コードは引き続き期待どおりに実行されるため、JavaScriptでは状況が明らかに異なります。
その理由は、JavaScriptフォームクロージャの関数であるためです。 クロージャは、関数と、関数が宣言されている字句環境の組み合わせです。環境には、クロージャーが作成されたときにスコープ内にあったローカル変数が含まれています。この例でmyFunc
は 、実行 makeFunc
中に作成されたdisplayName
関数インスタンスへの 参照です。displayName
のインスタンスはname
、変数が存在する字句環境への参照を維持します 。したがって、 myFunc
呼び出されたとき、変数name
は引き続き使用可能であり、その値 Mozilla
が変数に 渡されalert
ます。
これはもっと興味深い例です— makeAdder
関数:
function makeAdder(x) {
return function(y) {
return x + y;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12
この例では、makeAdder(x)
1つのパラメーターを受け入れx
、新しい関数を返す関数を 定義しました 。返される関数は1つのパラメーターy
を受け入れ x+y
、値を返します。
基本的に、これmakeAdder
は関数ファクトリです。彼は、指定された値とそのパラメーターを加算および合計する関数を作成します。上記の例では、関数ファクトリを使用して2つの新しい関数を作成しました。1つはパラメータを5に合計し、もう1つは10に合計します。
add5
と add10
は両方とも閉鎖です。それらは同じ関数定義を共有しますが、異なる字句環境を保存します。では add5
環境、それはx
5です。では add10
真ん中、それはx
10です。
閉鎖にはいくつかの穴があります
参照:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures