この有効範囲とは、let や const を使って宣言された変数や定数にアクセスできる範囲のことです。
基本的には有効範囲内の変数や定数にアクセスできても、有効範囲外のものにはアクセスすることは出来ません。
一見不便に感じるスコープですが、これがあることによって、複数人で作業する場合に変数名の衝突を避けることができたり、局所的に使用するつもりで宣言した変数の予期せぬ上書きやアクセスを防ぐメリットがあります。
この記事では
スコープの種類や有効範囲、グローバル変数やローカル変数など、スコープについての基本的なことを中心に解説していきます。
変数と定数のスコープ
変数や定数のスコープとは、変数(定数)にアクセスできる有効範囲のことです。
スコープには、大きく分けて グローバルスコープ と ローカルスコープ の2種類があり、ローカルスコープ にはさらに ブロックスコープ と 関数スコープ があります。
グローバルスコープは、どこからでもアクセスできるスコープのことで、ローカルスコープは、グローバルスコープ以外の局所的なアクセスが可能なスコープのことです。
そして ローカルスコープ の内、 関数スコープ は関数で使用する {}(波括弧)の中の部分を、 ブロックスコープ は関数スコープ以外の {}(波括弧)の中の部分を指します。
それでは実際に確認してみましょう。
以下のコードは、グローバルスコープと関数スコープ、ブロックスコープの混在したコードです。
それぞれのコンソール内の変数が何を出力するかを確認してみます。
</>javascriptlet test = 'グローバルスコープ';
function myFunc(){
let test = '関数スコープ';
console.log('階層2:',test); //関数スコープ
if(true){
let test = 'ブロックスコープ';
console.log('階層1:',test); //ブロックスコープ
}
}
console.log('階層3:',test); //グローバルスコープ
myFunc();
「let」を使って同じ階層で同じ変数を宣言することを再宣言と言い、通常は構文エラーになります。
しかし今回の例では、同じ変数でも階層が違うため、それぞれのスコープ内の変数が参照され出力されています。
グローバル変数(定数) と ローカル変数(定数)
変数のスコープを学ぶ際に、覚えておくべき用語があります。
それが グローバル変数(定数) と ローカル変数(定数) です。
グローバル変数(定数)とは、スコープの外で宣言された変数(定数)で、全ての場所からアクセス出来ます。
ローカル変数(定数)とは、スコープの中で宣言された変数(定数)で、そのスコープ内でのみ有効です。
スコープの有効範囲
スコープ内で宣言した変数(定数)は、先ほど確認した通り同じ階層内で有効ですが、自身のいるスコープよりも下の階層でも有効となっています。
しかし、自身のいるスコープよりも上の階層で参照しようとするとエラーになってしまうので注意が必要です。
それでは実際に確認してみましょう。
下の階層で参照する場合
次のコードは、関数の外側(上の階層)で宣言した変数を、スコープの内側(下の階層)で参照しています。
</>javascriptlet test3 = 'グローバルスコープ';
function myFunc(){
let test2 = '関数スコープ';
if(true){
let test1 = 'ブロックスコープ';
console.log(test1); //ブロックスコープ
console.log(test2); //関数スコープ
console.log(test3); //グローバルスコープ
}
}
myFunc();
一番外側(上の階層)の変数はグローバル変数なので、どこからでもアクセス可能ですが、下の階層の関数スコープ内で宣言した変数が、さらに下の階層のif文内のブロックスコープでも有効なのが見てとれます。
上の階層で参照する場合
次に、宣言した変数を上の階層で参照するとどうなるでしょうか。
次のコードは、スコープの内側(下の階層)で宣言した変数をスコープの外側(上の階層)で参照しています。
</>javascriptfunction myFunc(){
if(true){
let test1 = 'ブロックスコープ';
}
}
myFunc();
console.log(test1); //Uncaught ReferenceError
ご覧の通り、宣言したスコープの上の階層で変数を参照しようとすると、エラーが発生します。
変数の巻き上げ
javascriptでは、スコープの中で宣言した変数はスコープの先頭で宣言されたものとみなされます。
これを 巻き上げ または ホイスティング と言います。少しわかりづらいと思いますので実例を交えてご説明します。
まずこちらをご覧ください。
次の例では、スコープ内で変数の宣言をした後、コンソールで出力しています。
</>javascriptfunction myFunc(){
let test = 'ブロックスコープ';
console.log(test); //ブロックスコープ
}
myFunc();
結果は、通常通り変数の中身(ブロックスコープ)がそのままコンソールに出力されます。
今度は、変数の宣言をする前に参照してみましょう。
</>javascriptfunction myFunc(){ console.log(test); //Uncaught ReferenceError: Cannot access 'test' before initialization
let test = '関数スコープ';
}
myFunc();
「初期化前に 'test' にアクセスできません」というエラーメッセージが表示されました。
これはつまり、変数の宣言だけが先頭に移動され、まだ代入がされていない状態で参照しようとしているためです。
ちなみに、今回は let で宣言した場合を例に巻き上げの説明をしましたが、var で宣言する前に参照しようとした場合は、undefined が出力され、const の場合は let と同様にエラーが発生します。
最後に
いかがでしたでしょうか、今回はjavascriptの基本である変数と定数のスコープについて解説しました。
もっと詳しく学習したい方は、下の記事一覧から他の記事もご覧下さい。
Javascript
javascriptの基本的な使い方について解説した記事一覧ページです。
イラストを交えてやさしく解説していますので、ぜひご覧ください。続きを見る