ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScriptのスコープとクロージャの使い方を詳しく解説_基礎知識

JavaScriptのスコープとクロージャの使い方を詳しく解説_基礎知識

WBOY
WBOYオリジナル
2016-05-16 16:51:11924ブラウズ

スコープのネストはスコープチェーンを形成し、関数のネストはクロージャを形成します。クロージャとスコープ チェーンは、JavaScript を他の言語と区別する重要な機能の 1 つです。

スコープ
JavaScript には、関数スコープとグローバル スコープの 2 種類のスコープがあります。

関数内で宣言された変数と関数のパラメーターは同じスコープ、つまり関数スコープを共有します。関数スコープの簡単な例:

コードをコピー コードは次のとおりです。

function foo() {
var bar = 1 ;
{
var bar = 2;
}
return bar; // 2
}

C などの他のブロックスコープ言語とは異なり、これは常に 2 を返します。

ブラウザーのグローバル スコープは、ウィンドウ オブジェクトとして理解できます (Node.js はグローバルです):

コードをコピーコードは次のとおりです。

var bar = 1;
function foo() {}
alert(window.bar) // 1
alert(window.foo) ) ; // "関数 foo() {}"

変数 bar と関数 foo は両方ともグローバル スコープに属し、両方とも window の属性です。

スコープ チェーン
JavaScript で変数にアクセスする場合、ローカル変数とパラメーターから開始され、グローバル スコープに到達するまでスコープを段階的に移動します。

コードをコピー コードは次のとおりです:

varscope = 0, zero = "global -scope" ;
(function(){
var スコープ = 1, one = "scope-1";
(function(){
var スコープ = 2, two = "scope-2" ";
(function(){
varscope = 3, three = "scope-3";
scope-1 global-scope
console.log([three, two, one, zero ].join(" "));
console.log(scope) // 3
}); 🎜> console.log(scope) // 2
});
console.log(typeof two); // 未定義
console.log(scope); // 1
})();
console.log(typeof one); 🎜>console.log(scope); // 0



最も内側の関数では、各変数をステップごとに調べて出力できます。関数の最後から 2 番目の層では、変数 3 がトラバーサルで見つからないため、unknown が出力されます。
簡単な例を挙げると、何かを買うためにお金を出そうとするとき、まず財布を触ります。もし持っていなければ、お父さんにそれを求めます。それはおじいちゃんに聞いてみるといいよ...そして、あなたのお父さんが何かを買うお金がないとき、彼はあなたのところにそれを求めに来ません。

クロージャ

ある関数で別の関数を定義することを関数の入れ子と呼びます。関数をネストするとクロージャが形成されます。

クロージャとスコープ チェーンは相互に補完し、関数をネストすると、チェーン関係に複数のスコープが作成されるだけでなく、クロージャも形成されます。


コードをコピー コードは次のとおりです。function binding(func, target) {
return function() {
func.apply(target, argument);
};
}



では、クロージャをどのように理解すればよいでしょうか?
外部関数は組み込み関数にアクセスできません

外部関数は組み込み関数のパラメータや変数にアクセスできません

ただし、組み込み関数は外部関数のパラメータや変数にアクセスできます

言い換えると、組み込み関数には、外部関数
前述のスコープ チェーンの例を見てみましょう。今回はクロージャの観点から理解します。


コードをコピー コードは次のとおりです:

var スコープ = 0, ゼロ = "グローバル スコープ";
(function(){
var スコープ = 1, one = "スコープ-1";
(function() {
varscope = 2, two = "scope-2";
(function(){
varscope = 3, three = "scope-3";
// スコープ 3 スコープ-2 スコープ-1 グローバルスコープ
console.log([three, two, one, zero].join(" "));
console.log(scope); // 3
}) ();
console.log(typeof three); // 未定義
console.log(scope) // 2
});
console.log(typeof two); / 未定義
console.log(scope); // 1
})();
console.log(typeof one); // 未定義
console.log(scope);

最も内側の関数は、内部および外部で定義されたすべての変数にアクセスできます。最後から 2 番目の層の関数は、最内層の変数にアクセスできません。同時に、最内層のスコープ = 3 の代入操作は、同じ名前の外部変数には影響しません。

クロージャを別の角度から理解してみましょう:

外部関数が呼び出されるたびに、埋め込み関数が一度作成されます。
作成されると、外部関数のスコープ (ローカル変数、パラメータなどのコンテキストを含む) が各埋め込み関数オブジェクトになります。外部関数が実行を完了して終了した後でも、内部状態の一部
次の例を参照してください:

コードをコピー コードは次のとおりです。

var i, list = [];
for (i = 0; i list.push(function(){
console.log(i);
});
}
list .forEach(function(func){
func();
});

予想される "1" と "2" の代わりに "2" が 2 回取得されます。これは、リスト内の 2 つの関数によってアクセスされる変数 i が、上位スコープ内の同じ変数であるためです。

この問題を解決するためにクロージャを使用するようにコードを変更しましょう:

コードをコピー コードは次のとおりです。

var i, list = [];
for (i = 0; i list.push((function(j){
) return function(){
console.log(j);
} ;
})(i));
}
list.forEach(function(func){
func();
});

外側の「即時実行関数」は、関数内にパラメーター j の形式で存在するパラメーター変数 i を受け取り、返された内部関数内の名前 j と同じ参照を指します。外側の関数が実行されて終了すると、パラメーター j (その値はこの時点での i の現在の値) が内側の関数の状態の一部となり、保存されます。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。