ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScriptの高度なレキシカルスコープとスコープチェーンの深い理解_基礎知識

JavaScriptの高度なレキシカルスコープとスコープチェーンの深い理解_基礎知識

WBOY
WBOYオリジナル
2016-05-16 17:09:51967ブラウズ

主な内容:
1. JavaScript 字句スコープの意味を分析します

2. 変数のスコープチェーンを解析します

3. 変数名がプロモートされるとどうなりますか?

最近、Chuanzhi Podcast で JavaScript コースについて説明したところ、多くの友人が JavaScript はとても簡単だけど使い方が分からないと感じていたので、主に皆さんと共有するためのコンテンツをいくつか用意しました。 JavaScript の高度な部分には、スコープ チェーン、クロージャ、関数呼び出しパターン、プロトタイプ、オブジェクト指向などについて説明します。基礎を理解する必要がある場合は、学生は http://net にアクセスしてください。学習用の無料ビデオをダウンロードするには、itcast.cn にアクセスしてください。早速、トピックに進みましょう。

1. ブロックレベルのスコープについて
JavaScript の変数スコープに関しては、私たちが通常使用する C 系言語とは異なります。たとえば、C# では、次のコード:


static void Main(string[] args)
{
if(true)
{
int num = 10;
}
System.Console.WriteLine(num);
}


このコードをコンパイルすると、「名前 num が現在のコンテキストに存在しない」ため合格しません。ここでの変数のスコープ は中括弧で制限されているため、ブロックレベルのスコープと呼ばれます。 .


ブロックレベルのスコープでは、すべての変数は定義の中括弧内にあり、定義の先頭から末尾までの

範囲内で使用できます。変数は中括弧の外側からアクセスできません。つまり、コード



コードをコピーします コードは次のとおりです。
if(true)
{
int num = 10;
System.Console.WriteLine(num);
}


変数の定義と使用が同じ中括弧内にあるため、ここからアクセスできます。

しかし、JavaScript では異なります。JavaScript にはブロックレベルのスコープという概念がありません。

2. JavaScript のスコープ

JavaScript では、次のコード:

コードをコピー コードは次のとおりです。if(true) {
var番号 = 10 ;
}
アラート(番号);



操作の結果は、ポップアップ ウィンドウ 10 です。では、JavaScript では変数のスコープはどのように制限されるのでしょうか?

2.1 関数による変数のスコープの制限

JavaScript では、関数のみが変数のスコープを制限できます。これはどういう意味ですか? つまり、JavaScript では、関数内で定義された変数には関数内でアクセスできますが、
には関数の外からアクセスできません。次のコードを参照してください。


コードをコピー

コードは次のとおりです。var func = function() { var num = 10;
};
try {
alert(num);
} catch ( e ) {
alert( e );
}



このコードを実行すると、変数 num が定義されていません。つまり、関数内で定義された変数は
関数内で自由に使用できます。値を割り当てる前に次のコードを見てください:



コードをコピーします

コードは次のとおりです: var func = function( ) {alert(num);
var num = 10;
alert(num);
};
try {
func();
} catch ( e ) {
alert( e );
}



このコードを実行すると、エラーはスローされません (未定義と 10 の 2 回)。
ここから、変数は関数内でのみアクセスできることがわかります。同様に、この関数内の関数にもアクセスできます。

2.2 子ドメインが親ドメインにアクセスします

前述のように、関数は変数のスコープを制限でき、関数内の関数はスコープのサブドメインになります。ドメイン

の子コードは親ドメインの変数にアクセスできます。以下のコードを参照してください:


コードをコピー

コードは次のとおりです。var func = function() { var num = 10; var sub_func = function() {
alert(num);
};
sub_func();
};
func();

このコードの実行結果は 10 です。ただし、次のコードに示すように、子ドメイン内の親ドメインの
コードへのアクセスも条件付きです。 🎜>

コードをコピーします コードは次のとおりです。
var func = function() {
var num = 10;
var sub_func = function() {
var num = 20;
alert(num);
};
sub_func();
};
関数();

このコードには、前のコードよりも「var num = 20;」が 1 つ増えています。このコードはサブドメイン内にあるため、親ドメインにアクセスするサブドメインの状況が変わりました。このコードでは、結果は 20 と表示されます。つまり、この時点でサブドメインがアクセスする num は、親ドメインではなく、サブドメイン内の変数です。

JavaScript で変数を使用する場合、JavaScript インタプリタはまず現在の
スコープ内で変数の定義を検索します。そうでない場合は、この変数が使用されます。親ドメインで変数を探します。

以下のコードを見てください。最上位のスコープが見つからない場合は、「変数が定義されていません」という例外がスローされます。 🎜>



コードをコピーします

コードは次のとおりです。(function() { var num = 10; (function() {
var num = 20;
(function(){
alert(num);
})()
})();
})();



このコードを実行すると、"var num = 20;" を削除すると 20 が出力され、同様に
"var num = 10" を削除すると Error が表示されます。 .

3. スコープチェーン

JavaScript のスコープを分割することで、JavaScript のアクセススコープをチェーンツリー構造に接続することができます。を明確に理解できれば、JavaScript の変数とクロージャも非常に明確になります。以下では、描画メソッドを使用してスコープ チェーンを描画します。
3.1 描画ルール:
1) スコープ チェーンはオブジェクトの配列です
2) すべてのスクリプトはレベル 0 チェーンであり、各オブジェクトは位置を占めます
3) いつでも関数がチェーンを拡張するときは、レベルごとに展開します

4) アクセスするとき、最初に現在の関数を確認します。定義されていない場合は、上位レベルのチェーンを確認します

5) レベルまで繰り返します。 0 チェーン
3.2 例

次のコードを見てください:


コードをコピーします

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

var num = 10;var func1 = function () { var num = 20; var func2 = function() { var num = 30;
alert(num);
};
func2( );
};
var func2 = function() {
var num = 20;
var func3 = function() {
alert(num);
};
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 ] };// 擬似コードを使用してここに記述します-> Chain

var link_2 = { func2: [ num ] };// 疑似コードを使用して
-> を記述します。 2 番目のレベル 1 チェーンは変数が定義されておらず、空のチェーンであるため、 var link_2 = { func3: [ ] };
-> 上記のコードを統合すると、スコープ チェーンは次のように表現できます。




コードをコピー


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

// 疑似コードで記述しますvar link = [ // レベル 0 chain num, { func1 : [ // 最初のレベル 1 チェーン num, { func2 : [ // レベル 2 チェーン
num
] }
]},
{ func2 : [ / / 最初のレベル チェーン 2 つのレベル 1 チェーン
num,
{ func3 : [] }
]}
];

-> represented by image as

JavaScriptの高度なレキシカルスコープとスコープチェーンの深い理解_基礎知識

Picture: 01_01 scope chain.bmp

Note: Use js code to express the chain diagram, and it will be very clear when highlighted.

With this diagram of the scope chain, you can clearly understand how to access variables:
When you need to use a variable, first look for the variable on the current chain, and if you find it, use it directly. It will not
look up again; if it is not found, then it will search up the one-level scope chain until the 0-level scope chain.


If you can clearly determine the level of the scope chain to which a variable belongs, it will be very easy when analyzing JavaScript
code and using advanced JavaScript features such as closures (at least for me) .

3. Variable name promotion and function name promotion

With scope chain and variable access rules, there is a very thorny problem. First look at the JavaScript code of
below:

Copy code The code is as follows:

var num = 10;
var func = function () {
alert(num);
var num = 20;
alert(num);
};
func();

What will be the execution result? You can think about it, I won’t reveal the answer yet.

Let’s analyze this code first.
There is a level 0 scope chain in this code, which has the members num and func. Under func is a level 1 scope chain, which has the member num. . Therefore, when the function func is called, it will be detected that the
variable num is defined in the current scope, so this variable will be used. However, num is not assigned a value at this time, because the code
is It runs from top to bottom. Therefore, the first print is undefined, and the second print is 20.
Did you get the answer right?

It is also a common

problem in JavaScript to define code like this at the back and use it in the front. At this time, it is as if the variable is defined at the beginning, and the result is like the following code:

Copy code The code is as follows:
var num = 10;
var func = function() {
var num; // It feels like it has been defined here, but there is no assignment.
alert(num);
var num = 20;
alert(num);
};
func();

Then this phenomenon is often called variable name promotion. There is also function name promotion. For example, the following code:


Copy code The code is as follows:
var func = function() {
alert("Call external function");
};
var foo = function() {
func();

var func = function() {
alert("Call internal function");
};

func();
};

Okay, what is the result of this code? Or there should be something different, I won’t leave it to the readers to think about it!

I’ll answer the question in the next article.

Due to these differences, during actual development, it is recommended to write all variables at the beginning.

That is, the variables are defined at the beginning of the function, similar to the regulations of C language. This This is also done in js libraries
, such as jQuery, etc.

4. Summary

Okay, this article mainly explains what the lexical scope of JavaScript is all about, and explains

how to analyze the scope chain and variable access. Finally, let’s finish with one exercise! ! !

Look at the result of executing the following code:


Copy the code The code is as follows:
if ( ! "a" in window ) {
var a = "Define variable";
}
alert(a);

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