前の紹介で、JavaScript にはブロックレベルのスコープはなく、関数レベルのスコープのみがあることをすでに知っています。
JavaScript には明示的な名前空間もありません。つまり、すべてがグローバル スコープで定義されます。変数が参照されるたびに、JavaScript は変数が見つかるまでグローバル スコープ全体を走査します。グローバル スコープ全体を走査しても変数が見つからない場合は、ReferenceError がスローされます。
画像の説明を入力してください
暗黙的なグローバル変数
上記の 2 つの例は、異なる効果を生み出します。 1 つ目はグローバル スコープで変数 foo を定義し、2 つ目は現在のスコープで変数 foo を定義します。
キーワード var を使用しないと、予期しない影響が生じることに注意する必要があります。
関数テストでは変数 foo の定義に var が使用されていないため、関数外のグローバル変数 foo は上書きされます。大きな問題のようには見えないかもしれませんが、コードが数千行ある場合、これを追跡するのは困難なバグになる可能性があります。
上記の例では、サブループ関数内の変数 i が外側のグローバル変数 i を上書きするため、外側のループは最初の実行時に停止します。このエラーを回避するには、関数内に var を追加するだけで済みます。そのため、変数を定義するときにキーワード var を忘れずに追加してください。本当に外部グローバル変数に影響を与えたくない場合は除きます。
ローカル変数
JavaScript のローカル変数は 2 つの方法でのみ生成できます。1 つはキーワード var を使用して宣言する方法、もう 1 つは関数の仮パラメータとして生成する方法です。
このとき、関数 test 内の変数 i と foo はローカル変数であり、bar は外部グローバル変数 bar を上書きします。
吊り上げ
JavaScript は変数宣言をホイストします。これは、var 式と関数宣言の両方がスコープの先頭にホイストされることを意味します。
上記のコードを実行する前に、var 式と関数 test の宣言が先頭に昇格されるため、プログラムは正常に実行され、エラーは報告されません。
JavaScript にはブロックレベルのスコープがないため、var 式が高度になるだけでなく、if 構造も直感的ではなくなります。
上の例では、 if がグローバル変数 goo を操作しているように見えますが、実際には、変数 goo はプロモートされているため、変更されるのはローカル変数です。
ホイスティングのルールを理解していないと、次のコードは ReferenceError をスローすると思うかもしれません。
もちろん、コードが実行される前に var 式が先頭に昇格されているため、上記のコードにはエラーはありません。
@nightire Fan Ge のブログ投稿「JavaScript を理解する (2)」をおすすめします。この記事では改善点について非常に詳しく説明しています。
名前解決の順序
関数スコープ内で foo 変数にアクセスしようとすると、JavaScript は次の順序で検索します:
現在のスコープに var foo の定義があるかどうか。
関数パラメータに foo 変数があるかどうか。
関数自体の名前が foo であるかどうか。
外部ドメインにジャンプして最初の部分から検索します。
ネームスペース
最も一般的な問題の 1 つは名前の競合です。これは、Javascript のグローバル スコープが 1 つだけであることが原因で発生します。しかし、この問題は匿名の外部関数によって解決できます。
上記の例の匿名関数は式とみなされ、実行されます。
もちろん、別の方法で関数式を呼び出すこともできます。構造は異なりますが、結果は同じです。
概要
匿名外部関数を使用してコードをスペースにカプセル化することをお勧めします。これにより、名前空間の競合が解決されるだけでなく、プログラムのモジュール化も容易になります。
さらに、グローバル変数の使用は、保守にコストがかかり、エラーが発生しやすいため、推奨されません。
名前空間の型、関数、変数、テンプレートなどはすべてエンティティに属します。
エンティティに共通する主な点は、エンティティに名前を付けることができることです。 (また、ラベルには名前を付けることもできますが、それは実体ではありません。)
名前空間スコープは、ブロック スコープ、クラス スコープ、関数プロトタイプ スコープ、関数スコープ (ラベルにのみ有効) と同様に、スコープの種類の総称です。名前空間内で宣言された名前は、名前空間スコープ内にあります。グローバル名は、暗黙的なグローバル名前空間スコープ内にあるとみなされます。
ネームスペースの役割は確かにスコープですが、同じネームスペースを複数の場所で複数回宣言できますが、それらの内容は最終的に 1 つの名前に結合されます。スペース、std と同じように、どこにでもマクロ定義