主な内容:
1. JavaScript の字句スコープの意味を分析する
2. 変数のスコープチェーンを解析する
3. 変数名がプロモートされるとどうなりますか?
最近、Chuanzhi Podcast で JavaScript コースについて説明していたところ、多くの友人が JavaScript はとても簡単だけど使い方が分からないと感じていたので、いくつかのコンテンツを用意しました。
このシリーズでは主に、スコープ チェーン、クロージャ、関数呼び出しパターン、プロトタイプ、オブジェクト指向など、JavaScript の高度な部分について説明します。基礎を知りたい場合は、http を参照してください。 : //net.itcast.cn にアクセスして、学習用の無料ビデオをダウンロードしましょう。早速、本題に進みましょう。
1. ブロックレベルのスコープについて
JavaScript の変数スコープに関して言えば、私たちが普段使用している C 系言語とは異なります。
たとえば、C# の次のコード:
次のようにコードをコピーします。
static void Main(string[] args)
{
もし(真)
{
int num = 10;
}
System.Console.WriteLine(num);
}
このコードをコンパイルすると、「名前 num が現在のコンテキストに存在しない」ため、パスしません。
変数のスコープは中括弧で制限され、ブロックレベルスコープと呼ばれます。
ブロックレベルのスコープでは、定義の先頭から中括弧の終わりまで、すべての変数が定義の中括弧内にあります。
スコープ内で使用できます。つまり、このスコープの外からはアクセスできません。
次のようにコードをコピーします。
もし(真)
{
int num = 10;
System.Console.WriteLine(num);
}
変数は同じ中括弧内で定義および使用されているため、ここでアクセスできます。
しかし、JavaScript では異なります。JavaScript にはブロックレベルのスコープという概念がありません。
2. JavaScriptのスコープ
JavaScript では、次のコードになります。
次のようにコードをコピーします。
if(true) {
varnum = 10;
}
アラート(番号);
操作の結果は、ポップアップ ウィンドウ 10 です。では、JavaScript では変数のスコープはどのように制限されるのでしょうか?
2.1 変数の範囲を制限する関数
JavaScript では関数のみが変数のスコープを制限できます。これはどういう意味ですか?
つまり、JavaScript では、関数内で定義された変数には関数内ではアクセスできますが、関数の外ではアクセスできません。
アクセスできません。次のコードを参照してください。
次のようにコードをコピーします。
var func = function() {
varnum = 10;
};
試す {
アラート(番号);
} キャッチ (e) {
アラート(e);
}
このコードを実行すると例外がスローされ、変数 num は定義されません。つまり、関数内で変数を定義できません。
関数の外で使用することはもちろん、代入前でも関数内で自由に使用できます。次のコードを参照してください。
次のようにコードをコピーします。
var func = function() {
アラート(番号);
varnum = 10;
アラート(番号);
};
試す {
関数();
} キャッチ (e) {
アラート(e);
}
このコードを実行すると、エラーはスローされず、ポップアップ ウィンドウが未定義と 10 の 2 回表示されます (理由については後述します)。
ここから、変数は関数内でのみアクセスできることがわかります。同様に、関数内の関数にもアクセスできます。
2.2 サブドメインが親ドメインにアクセスする
前述したように、関数は変数のスコープを制限できるため、関数内の関数はサブドメインのサブドメインになります。
のコードは親ドメインの変数にアクセスできます。次のコードを参照してください。
次のようにコードをコピーします。
var func = function() {
varnum = 10;
var sub_func = function() {
アラート(番号);
};
sub_func();
};
関数();
このコードの実行結果は 10 です。ただし、子ドメインで親ドメインにアクセスすると、上記の変数アクセスが表示されます。
次のコードのように、コードにも条件があります。
次のようにコードをコピーします。
var func = function() {
varnum = 10;
var sub_func = function() {
ヴァルナム = 20;
アラート(番号);
};
sub_func();
};
関数();
このコードには、以前よりも「var num = 20;」が 1 つ増えています。このコードはサブドメイン内にあるため、サブドメインは親ドメインにアクセスします。
変更があり、このコードによって出力される結果は 20 です。つまり、現時点でサブドメインによってアクセスされる num は、親ドメインではなく、サブドメイン内の変数です。
JavaScript で変数を使用する場合、最初に JavaScript インタプリタがアクセスするための特定の規則があることがわかります。
ユーザー ドメインを検索して変数の定義があるかどうかを確認し、存在しない場合はこの変数を使用し、親ドメインで変数を検索します。
同様に、トップレベルのスコープが見つからない限り、「変数が定義されていません」という例外がスローされます。次のコードを参照してください。
次のようにコードをコピーします。
(関数() {
varnum = 10;
(関数() {
ヴァルナム = 20;
(関数(){
アラート(番号);
})()
})();
})();
このコードを実行すると、「var num = 20;」が削除されると、同様に 10 が出力されます。
「var num = 10」の場合、未定義エラーが発生します。
3. スコープチェーン
JavaScript スコープを分割すると、JavaScript アクセス スコープをチェーン ツリー構造に接続できます。
JavaScript のスコープ チェーンを明確に理解できれば、JavaScript の変数とクロージャも非常に明確になります。
次のメソッドでは、描画を使用してスコープ チェーンを描画します。
3.1 描画ルール:
1) スコープチェーンはオブジェクトの配列です
2) すべてのスクリプトはレベル 0 チェーンであり、各オブジェクトは 1 つの位置を占めます。
3) 関数がチェーンに拡張されている場合は、それをレベルごとに拡張します。
4) アクセスするときは、まず現在の関数を確認します。定義されていない場合は、チェーンを確認します。
5) レベル 0 チェーンになるまでこれを繰り返します
3.2 例
以下のコードを見てください。
次のようにコードをコピーします。
varnum = 10;
var func1 = function() {
ヴァルナム = 20;
var func2 = function() {
ヴァルナム = 30;
アラート(番号);
};
func2();
};
var func2 = function() {
ヴァルナム = 20;
var func3 = function() {
アラート(番号);
};
func3();
};
func1();
func2();
このコードを分析してみましょう:
-> まず第一に、コード全体がグローバル スコープであり、レベル 0 スコープ チェーンとしてマークできます。次に、配列があります。
var link_0 = [ num, func1, func2 ]; // ここでは疑似コードで説明します。
-> ここで func1 と func2 はどちらも関数であるため、2 つのレベル 1 スコープ チェーンが導出されます。
var link_1 = { func1: [ num, func2 ] } // ここでは擬似コードで説明します。
var link_1 = { func2: [ num, func3 ] } // ここでは擬似コードで説明します。
-> 最初のレベル 1 チェーンはレベル 2 チェーンから派生します。
var link_2 = { func2: [ num ] } // ここでは疑似コードで説明します。
-> 2 番目のレベル 1 チェーンには変数が定義されておらず、空のチェーンであり、次のように表現されます。
var link_2 = { func3: [ ] };
-> 上記のコードを統合すると、スコープチェーンは次のように表現できます。
次のようにコードをコピーします。
//ここでは擬似コードで説明します
var link = [ // レベル 0 チェーン
番号、
{ func1 : [ // 最初のレベル 1 チェーン
番号、
{ func2 : [ // レベル 2 チェーン
番号
] }
]}、
{ func2 : [ // 2 番目のレベル 1 チェーン
番号、
{ 機能 3 : [] }
]}
];
-> イメージとして表現すると、
図: 01_01 スコープチェーン.bmp
注: チェーン図を表現するには js コードを使用します。強調表示すると非常に明確になります。
このスコープ チェーン図を使用すると、変数へのアクセスがどのように実行されるかを明確に理解できます。
変数を使用する必要がある場合は、まず現在のチェーンで変数を検索します。見つかった場合は、それを直接使用します。
上方向に検索し、見つからない場合は、1 レベルのスコープ チェーンを 0 レベルのスコープ チェーンまで検索します。
変数が属するスコープ チェーンのレベルを明確に判断できる場合は、JavaScript を分析するときに
コーディングやクロージャなどの高度な JavaScript 機能の使用に関しては (少なくとも私にとっては) 非常に簡単です。
3. 変数名昇格と関数名昇格
スコープチェーンと変数アクセスルールに関しては、まず次のような非常に難しい問題があります。
JavaScript コード:
次のようにコードをコピーします。
varnum = 10;
var func = function() {
アラート(番号);
ヴァルナム = 20;
アラート(番号);
};
関数();
実行の結果はどうなるでしょうか?考えてみてください。答えはまだ明かしません。
まずこのコードを分析してみましょう。
このコードにはレベル 0 のスコープ チェーンがあり、メンバー num と func が含まれており、func の下にレベル 1 の関数があります。
メンバー num を含むドメイン チェーン。したがって、関数 func が呼び出されると、現在のスコープで検出されます。
変数 num が定義されているため、この変数が使用されます。ただし、コードではこの時点では num には値が割り当てられません。
コードは上から下に実行されるため、最初の出力は未定義で、2 番目の出力は 20 になります。
正しく理解できましたか?
JavaScript では、このように後ろでコードを定義し、それを前で使用することも一般的です
質問です。この時点では、最初に変数が定義されているかのようになり、結果は次のコードのようになります。
次のようにコードをコピーします。
varnum = 10;
var func = function() {
var num;// ここで定義されているように感じますが、代入はありません。
アラート(番号);
ヴァルナム = 20;
アラート(番号);
};
関数();
この現象は、変数名プロモーションと呼ばれることがよくあります。たとえば、次のようなコードもあります。
次のようにコードをコピーします。
var func = function() {
alert("外部関数の呼び出し");
};
var foo = function() {
関数();
var func = function() {
alert("内部関数の呼び出し");
};
関数();
};
さて、このコードはどのようになりますか?あるいは、何か違うことがあるはずです。読者に考えてもらうつもりはありません。
答えは次の記事でお伝えします。
このような違いがあるため、実際の開発では最初にすべての変数を記述することをお勧めします。
つまり、C言語の規定と同様に関数の先頭で変数を定義します。これはjsライブラリでも同様です。
これはjQueryなどで行われます。
4. まとめ
さて、この記事では主に JavaScript のレキシカルスコープとは何か、そしてその説明について説明します。
スコープ チェーンと変数のアクセス ステータスを分析する方法、最後の演習を残して終了しましょう。 ! !
以下のコードを実行した結果がどのようになるかを確認してください。
次のようにコードをコピーします。
if( ! ウィンドウ内の "a" ) {
var a = "変数を定義";
}
アラート(a);