以前の紹介では、JavaScriptにはブロックレベルの関数がなく、関数レベルの範囲のみがあることがすでにわかっています。
コードコピーは次のとおりです。
function test(){//スコープ
for(var i = 0; i <10; i ++){//スコープではありません
// count
}
console.log(i); // 10
}
また、JavaScriptに表示される名前空間はありません。つまり、すべてがグローバル範囲で定義されています。変数が参照されるたびに、JavaScriptは、見つかるまでグローバルスコープ全体を通過します。変数が完全なグローバルスコープでまだ見つからない場合、参照エラーエラーがスローされます。
写真の説明を入力してください
暗黙のグローバル変数
コードコピーは次のとおりです。
//スクリプトa
foo = '42';
//スクリプトb
var foo = '42'
上記の2つの例には、効果が異なります。 1つ目は、グローバルスコープの変数FOOを定義し、2番目は現在の範囲で変数FOOを定義します。
キーワードvarを使用しない場合、予期しない影響があることに注意する必要があります。
コードコピーは次のとおりです。
//グローバルスコープ
var foo = 42;
function test(){
//ローカルスコープ
foo = 21;
}
テスト();
foo; // 21
VARは関数テストで変数FOOを定義するために使用されないため、関数外のグローバル変数FOOが上書きされます。それは大きな問題のようには見えませんが、何千ものコードがある場合、追跡するのは難しいバグになります。
コードコピーは次のとおりです。
//グローバルスコープ
var items = [/ * some list */];
for(var i = 0; i <10; i ++){
subloop();
}
関数subloop(){
// subloopの範囲
for(i = 0; i <10; i ++){// varステートメントの欠落
//素晴らしいことをしてください!
}
}
上記の例では、Subloop関数内の変数Iが外部グローバル変数iをオーバーライドするため、最初の実行が実行されると外部ループが停止します。このエラーを回避するために関数内にVARを追加する必要があるため、変数を定義するときにキーワードVARを追加することを忘れてはなりません。外部のグローバル変数に影響を与えたい場合を除きます。
ローカル変数
JavaScriptのローカル変数は2つの方法でのみ生成できます。1つはキーワードVARを介して宣言され、もう1つは関数の正式なパラメーターとして使用されます。
コードコピーは次のとおりです。
//グローバルスコープ
var foo = 1;
var bar = 2;
var i = 2;
関数テスト(i){
//関数テストのローカル範囲
i = 5;
var foo = 3;
bar = 4;
}
テスト(10);
この時点で、関数テスト内の変数IとFOOはローカル変数であり、BARは外部のグローバル変数バーをオーバーライドします。
巻き上げ
JavaScriptは可変宣言を促進します。つまり、VAR式と関数宣言の両方がスコープの最上部に宣伝されます。
コードコピーは次のとおりです。
バー();
var bar = function(){};
var somevalue = 42;
テスト();
関数テスト(データ){
if(false){
goo = 1;
} それ以外 {
var goo = 2;
}
for(var i = 0; i <100; i ++){
var e = data [i];
}
}
上記のコードが実行される前に、VAR式と関数テストの宣言が上部に宣伝されるため、プログラムは正常に実行され、エラーが報告されません。
コードコピーは次のとおりです。
// varステートメントはここに移動しました
var bar、somevalue; //デフォルト「未定義」にデフォルト
//関数宣言も上昇しました
関数テスト(データ){
var goo、i、e; //欠落ブロックスコープはこれらをここで移動します
if(false){
goo = 1;
} それ以外 {
Goo = 2;
}
for(i = 0; i <100; i ++){
e = data [i];
}
}
バー(); // barはまだ「未定義」であるため、typeRrorで失敗します
somevalue = 42; //割り当ては巻き上げの影響を受けません
bar = function(){};
テスト();
JavaScriptにはブロックレベルの範囲がないため、これによりVAR式が改善されるだけでなく、IF構造の直感を低下させます。
上記の例では、グローバル変数Gooで動作している場合、実際には可変Gooが宣伝されて以来、ローカル変数が変更されているようです。
標高ルールを理解していない場合は、次のコードが参照エラーエラーをスローすると思われる場合があります。
コードコピーは次のとおりです。
//重要なものが初期化されているかどうかを確認します
if(!somemportantthing){
var someimportantthing = {};
}
もちろん、上記のコードは間違っていません。なぜなら、コードが実行される前にVAR式が上部に宣伝されているためです。
コードコピーは次のとおりです。
varmoterportantthing;
//他のコードは、ここで重要なものを初期化するかもしれません
//そこにあることを確認してください
if(!somemportantthing){
someimportantthing = {};
}
ここでは、 @nightire Fan GEのブログ投稿「JavaScript(II)の理解」をお勧めします。これは、改善を非常に徹底的に説明しています。
名前解決順序
関数範囲内でFOO変数にアクセスしようとすると、JavaScriptは次の順序でそれを探します。
現在の範囲にvar fooの定義があるかどうか。
関数パラメーターにFOO変数があるかどうか。
関数自体がfooであるかどうか。
外側の定義ドメインにジャンプして、最初の部分から見上げ始めます。
名前空間
JavaScriptにはグローバルな範囲が1つしかないため、最も一般的な問題の1つは競合の命名です。しかし、この問題は、匿名の外部関数によって解決できます。
コードコピーは次のとおりです。
(関数() {
//セルフが含まれている「名前空間」
window.foo = function(){
//露出した閉鎖
};
})(); //すぐに関数を実行します
上記の例の匿名関数は式と見なされるため、実行されます。
コードコピーは次のとおりです。
(//親の内部の関数を評価します
関数() {}
)//関数オブジェクトを返します
()//評価の結果を呼び出します
もちろん、他の方法を使用して、機能式、異なる構造を呼び出すこともできますが、同じ効果もあります。
コードコピーは次のとおりです。
//直接呼び出すための他のいくつかのスタイル
!関数(){}()
+function(){}()
(関数(){}());
// 等々...
要約します
匿名の外部関数を使用して、コードをスペースにカプセル化することをお勧めします。スペースには、名前空間の競合を解決するだけでなく、プログラムのモジュール化も促進します。
さらに、グローバル変数を使用することは良い習慣ではなく、メンテナンスコストが高く、エラーが発生しやすくなります。
名前空間には、同じタイプ、関数、変数、テンプレートなどがあり、すべてエンティティに属します。
エンティティの主な共通性は、名前を持つことができるということです。 (さらに、タグには名前を付けることもできますが、エンティティではありません。)
名前空間スコープは、ブロックスコープ、クラススコープ、関数プロトタイプスコープ、および関数スコープ(ラベルに対してのみ有効)と並行するスコープの一般的な用語です。名前空間内で宣言された名前は、名前空間範囲内にあります。グローバル名は、暗黙のグローバル名空間範囲で考慮されます。
名前空間の機能は確かに範囲ですが、単純な範囲とは異なります。複数の場所で同じ名前空間を複数回宣言することはできますが、内部のコンテンツを再定義することはできません。彼らは最終的に、STDと同じように、どこでもマクロ定義と同じように名前空間を合成します。