JavaScriptの変数スコープを理解する
スコープは、変数または関数の実行コンテキストです。 アクセスできるデータを定義します。 この概念はかなり単純に見えるかもしれませんが、いくつかの重要な微妙な点があります。
JavaScriptには、従来、グローバルスコープとローカルスコープの2種類のスコープがありました。 スコープの目的は、実行コンテキストがアクセスできるすべての変数と関数へのアクセスを提供することです。
グローバルスコープ
変数が関数の外部で宣言されると、その変数は自動的にグローバルスコープに属し、関数であれブロックであれ、プログラムのどこからでもアクセスできます。 また、必要に応じて、ブラウザで、プログラムの任意の場所でwindow.newVariable
として宣言することにより、グローバル変数を作成できます。
const nestAnimal = 'crocodilian'; // belongs to the Global scope function getNestInfo(){ window.eggs = 5; // as well belongs to the Global scope }
実際、ブラウザでは、グローバルスコープの変数はグローバルwindow
オブジェクトに属しています。
JavaScriptはガベージコレクションされた言語であり、コンテキストでプログラムを実行している間、すべての変数を利用可能に保ち、後で削除します。 変数のライフサイクルを考えてみましょう。 変数は、関数の実行中に存在します。 変数は関数内で使用され、関数は終了します。 その時点で、この変数は不要になったため、そのメモリを再利用でき、JavaScriptによってこの変数がメモリから削除されます。 ただし、グローバル変数は、アプリケーションの実行中は常にメモリに残り、アプリケーションを詰まらせるため、プログラムの速度が低下します。また、予期しない名前の競合が発生する可能性があります。
つまり、可能な限り、グローバル変数の定義を避ける必要があります。 これらは非常に特殊な場合にのみ本当に必要になるため、これには注意してください。
ローカルスコープ
ES6は、constおよびletキーワードを使用してブロックスコープ変数を導入しました。 これらのキーワードを使用すると、ローカルスコープが作成され、それを囲む最も内側のブロック内に存在します。 関数、for
ループ、while
ブロック、if
ブロックなどが考えられます。 このようなローカルスコープの変数には、そのブロック内からのみアクセスできます。
各ブロックには独自の実行コンテキストがあり、アクセスできるデータとその動作を定義します。 コードがコンテキストで実行されると、スコープチェーンが作成されます。 これには、そのブロック内で宣言されたすべての変数と関数が含まれ、次に、含まれている(親)コンテキストからのデータなどが含まれます。 このパターンは、グローバルコンテキストに到達するまで続きます。
例を見てみましょう:
let caymanMood = 'calm'; function changeMood(newMood){ if (caymanMood === 'calm'){ caymanMood = newMood; } else { caymanMood = 'calm'; } } changeMood('happy');
関数changeMood
には、独自の変数オブジェクト(引数オブジェクトnewMood
)とグローバルコンテキストの変数オブジェクトcaymanMood
の2つのオブジェクトを含むスコープチェーンがあります。 関数はスコープチェーンの一部であるため、caymanMood
にアクセスできます。
スコープチェーン拡張
グローバルおよびローカルの実行コンテキストに加えて、スコープチェーンを拡張することが可能です。 これは2つの方法で実行できます。
- ポイント1:withステートメント
- ポイント2:
try...catch
ステートメントのcatch
ブロック。
function buildNest() { const assets = 'grass'; with(reptilian){ const building = ability + assets; } return building; }
with
は、スコープチェーンの先頭に追加されるオブジェクトを作成しますが、コードを読んだときに、どのオブジェクトが正確に変更されるかを確実に知ることができないということです。 それはグローバル変数ability
でしょうか、それともこのコンテキストの変数reptilian.ability
でしょうか。 したがって、プログラムの正しい実行は保証されません。 with
ステートメントの使用は、紛らわしいバグや互換性の問題の原因となる可能性があるため、 MDN Webdocsでは推奨されていません。
catch
ステートメントは、スローされたエラーオブジェクトの宣言を含む新しい変数オブジェクトを作成し、このエラーオブジェクトはスコープチェーンの先頭に追加されます。
まとめ
これにより、JavaScriptでローカルスコープとグローバルスコープがどのように機能するか、そして可能な限り最も近いローカルコンテキストに依存することが、読みやすく保守しやすいコードを作成するための良いアイデアであるかを少しよく理解できるはずです。