今回の記事では、スコープについて解説します。
スコープは、JavaScriptに限らず、すべてのプログラミング言語で大切な概念です。スコープの仕組みを理解することで、より複雑なプログラムを記述することができるようになります。
さっそく学習していきましょう。
- グローバルスコープとローカルスコープ、2つのスコープの違い
- スコープチェーンについて
スコープとは
スコープとは、変数や関数などを定義する際に、どこまでその変数や関数を利用できるのかを決める範囲のことです。
- グローバルスコープ
- ローカルスコープ
JavaScriptには上記の2つのスコープが存在します。
次の章では、それぞれのスコープについて理解を深めていきましょう。
グローバルスコープ
グローバルスコープは、JavaScriptのどこからでもアクセスできるスコープのことをいいます。
グローバルスコープにある変数は、全ての関数の外側で宣言されています。グローバルスコープで定義した変数はグローバル変数と呼ばれ、プログラムのどこからでも参照できます。
let global = "グローバルスコープです!";
function sampleFnc() {
console.log(global); // -> "グローバルスコープです!"
}
sampleFnc();
console.log(global); // -> "グローバルスコープです!"
ローカルスコープ
グローバルスコープとは異なり、限定的に範囲が狭められたスコープのことをいいます。
- ブロックスコープ
- 関数スコープ
ローカルスコープには、以上の2つの種類があることを覚えてください。
ブロックスコープ
それでは、ブロックスコープについて確認していきましょう。
ブロックスコープは、「{}」で囲まれた部分でのみ有効なスコープです。
ブロックスコープの例
コンソール画面で、変数の値を表示するためのコードを記述しました。
{
// {}内で変数「sample」は参照できる
let sample = 'ブロックスコープです!';
console.log(sample); // 'ブロックスコープです!'
}
// スコープ外から変数「sample」は参照できない
console.log(sample); // ReferenceError: sample is not defined
「{}」で囲われた範囲内で宣言された変数は、その括弧内でのみ参照できるローカルスコープが適用されます。そのため、同じブロックスコープ内での「console.log()」では値を表示することができます。
それに対し、ブロックスコープ外の「console.log()」では、「変数が定義されていない」というエラーが出てしまいます。これは、変数「sample」がスコープの外にあって参照できないために発生するエラーです。
上記の例から、変数「sample」はブロックスコープ内でのみ有効になっていることが確認できました。
関数スコープ
次に、関数スコープについて確認していきましょう。
関数内で宣言された変数や関数は、その関数内のみでアクセスできるローカルスコープ、関数スコープが適用されます。
関数スコープの例
コンソール画面で、関数を使って値を表示するためのコードを記述しました。
function sampleFnc() {
let test = "関数スコープです!";
// 関数のスコープ内から変数「test」は参照できる
console.log(test); // => "関数スコープです!"
}
sampleFnc();
// 関数のスコープ外から変数「test」は参照できないためエラー
console.log(test); // => ReferenceError: arg is not defined
上記のコードでは、sampleFnc関数のブロック({})内で変数を定義しています。
変数「test」は、sampleFnc関数の「{}」で囲われたスコープでのみ有効な変数です。そのため、同じ関数スコープ内での「console.log()」では値を表示することができます。
一方で、関数スコープ外の「console.log()」では、変数が定義されていないのでエラーが出てしまいます。
引数がある関数スコープの例
次は、関数スコープ内で引数を使用する際のスコープを確認していきましょう。
関数を使って引数の値を表示するためのコードを記述しました。
function sampleFnc(argument) {
// 関数のスコープ内から引数「argument」は参照できる
console.log(argument); // => 1
}
sampleFnc(1);
// 関数のスコープ外から引数「argument」は参照できないためエラー
console.log(argument); // => ReferenceError: argument is not defined
上記のコードでは、sampleFnc関数のブロック({})内で引数を定義しています。
引数「argument」は、sampleFnc関数の「{}」で囲われたスコープでのみ有効な引数です。そのため、同じ関数スコープ内での「console.log()」では値を表示することができます。
一方で、関数スコープ外の「console.log()」では、引数が定義されていないのでエラーが出てしまいます。
スコープチェーン
次は、スコープチェーンについて学んでいきましょう。
スコープチェーンとは、スコープが階層構造になっている状態や参照する順番のことをいいます。
スコープチェーンは、下記の例のようにスコープが入れ子構造になった際に必要になる知識です。
スコープチェーンの例
{
//外側のスコープ
let sample = "外側にいるよ!";
{
//内側のスコープ
console.log(sample); // => "外側にいるよ!"
}
}
スコープがネスト(入れ子構造)になっている場合には、内側のスコープから外側のスコープにある変数を参照します。
上記のコードでは、内側のスコープから外側のスコープに定義されている変数「sample」を参照しています。
内側のスコープ
同じスコープ内に変数「sample」がない
⇒ 外側のスコープを参照しにいく
外側のスコープ
外側のスコープ内の変数「sample」を参照できたので、コンソールに出力する。
⇒ "外側にいるよ!"
こちらの例から、スコープの階層が違うと変数を参照する順番に変化があることがイメージできれば大丈夫です。
スコープの階層は異なるが、変数名が同じ例
次の例では、スコープの階層ごとに変数を記述し、内側と外側のスコープ両方に同じ名前の変数が定義されています。
{
const sample = "外側のスコープです!";
{
const sample = "内側のスコープです!";
console.log(sample); // => "内側のスコープです!"
}
// 最初に同じスコープ内の変数が参照される
console.log(sample); // => "外側のスコープです!"
}
上記の例では、スコープチェーンの仕組みにより、現在のスコープに定義されている変数「sample」が優先的に参照されます。
つまり、同じ階層にあるスコープが優先されます。外側から内側のスコープへと参照することはありません。
内側のスコープ
同じスコープ内の変数「sample」を参照してコンソールに出力する。
⇒ "内側のスコープです!"
外側のスコープ
同じスコープ内の変数「sample」を参照してコンソールに出力する。
⇒ "外側のスコープです!"
まとめ:スコープは変数を参照する範囲のこと
JavaScriptのスコープについて説明しました。内容を簡単にまとめます。
スコープのまとめ
スコープは変数や関数のアクセス範囲を制御する概念で、グローバルスコープ、関数スコープ、ブロックスコープの3種類がある。
範囲が制限されているスコープのことをローカルスコープという。括弧が入れ子になっているとき、スコープチェーンに従って、内側から外側に向かって順に変数を参照する。同じ階層が優先される。
コードが変数にアクセスする際、まず現在のスコープから外側のスコープへと順番に探し、最終的にグローバルスコープまで達した時点で該当する名前が見つからなければ、参照エラー(ReferenceError)が発生する。
スコープを理解することで、変数名の競合や変数同士の値の受け渡しの理解が深まり、より高度なプログラムを作成できるようになります。
今回の例でスコープについてのイメージを膨らませていただけたら幸いです。