変数を参照するとは?
そもそも変数を参照するということ自体がよく分からないという方に向けて、変数の参照についておさらいしてみたいと思います。
変数とは、データを入れておく箱のような物であり、文字列や数値など様々な型のデータを変数に格納することができます。
変数を宣言するには、以下のようにletを用います。(定数の場合はconst)
JavaScript
let greeting = "Hello, world!";
しかし、データを箱に入れただけでは、データを活用することができませんよね。
格納したデータを取り出して表示させたり、書き換えたり、何らかの手を加えることで初めて、データを活用することができます。
そして、データに何らかの手を加えるために変数にアクセスすることを、『参照する』と言います。
下のコードはgreetingという変数に文字列のデータを格納し、格納した変数greetingにアクセス(参照)してコンソール画面にデータ(文字列)を表示させるという処理です。
JavaScript
let greeting = "Hello, world!";
console.log(greeting); // Hello, world!
ここまでは改めて解説されなくても既に分かっているという方も多いでしょう。しかし、問題はここからです。
変数に格納したデータはどこからでも参照できるとは限りません。
宣言した変数は、宣言された場所によって有効範囲が決まっており、その有効範囲は『スコープ』という仕組みによって決定されます。
そして、そのスコープの外から変数を参照しようとしても参照できずにエラーになります。
たとえば、下のコードはエラーになります。
JavaScript
{
let greeting = "Hello, world!";
}
console.log(greeting); // エラー(greeting is not defined)
スコープの仕組みについての理解が足りないと、『変数をちゃんと宣言しているのになんでエラーになるの!?』と慌ててしまうことになりかねません。
ということで、次の章からはスコープにどのようなものがあるのか詳しく見ていこうと思います。
POINT!
- ・変数の参照=変数に格納したデータを活用するために変数にアクセスすること!
- ・変数はどこからでも参照できるとは限らない(宣言された場所による)!
- ・変数の有効範囲はスコープという仕組みによって決定される!
グローバルスコープとは
バグを発生させないためには、できるだけ変数の寿命を短くしておく=有効範囲を狭めておくことが基本です。
しかし、場合によってはどこからでも参照できるような仕組みも必要ですよね。
変数の有効範囲を限定しないスコープをグローバルスコープと言い、このスコープで宣言された変数はどこからでも参照することができます。
グローバルスコープとして変数を宣言するには、関数の中やブロック{ }(波括弧)で囲まれた中ではなく、その外側で宣言するようにします。
下は変数globalNumをグローバルスコープで宣言し、その変数を関数test()の中で参照している例です。
グローバルスコープ=どこからでも参照できるため、エラーは起こりません。
JavaScript
let grobalNum = 10;
function test() {
console.log(grobalNum);
}
test(); // 10
グローバルスコープで宣言された変数は、その性質上、変数を参照できない(有効範囲外である)ことによるエラーは起こりにくいです。
しかし、どこからでも書き換えることが可能であるため、不具合の原因になりやすいというデメリットもあるので注意が必要です。
先ほどのプログラムにちょっと手を加えるだけでも、下のようにやや混乱する結果になってしまいます。
JavaScript
let grobalNum = 10;
function test() {
console.log(grobalNum);
grobalNum += 1;
}
test(); // 10
test(); // 11
test()関数を2回実行しただけなのに、結果が変わってしまいましたね。
これがもっと複雑なプログラムになると、ワケがわからなくなるかもしれません。
どうしても必要な場合以外は、グローバルスコープではなく、次に紹介するような関数スコープなどで変数を宣言した方が良いでしょう。
POINT!
- ・グローバルスコープで宣言された変数は、どこからでも参照できる!
- ・グローバルスコープで変数を宣言するには、関数や{ }(波括弧)の外で宣言する!
- ・どこからでも参照できる反面、意図せず値が書き換えられてしまうなど不具合の原因にもなりやすい!
ブロックスコープとは
ブロックスコープとは、{ }(波括弧)で囲まれた部分が有効範囲となる仕組みです。
プログラミング言語では{ }でコードを囲む必要がある場面が多いです。
JavaScriptにおける代表的な例としては、if文があげられるでしょう。
- if文
- if(条件) { …処理… }
そして、このように{ }で囲まれた部分で宣言された変数は『ブロックスコープ内の変数』として管理され、{ }の外からは参照できません。
下はif文の外(ブロックスコープの外)から変数を参照しようとして、エラーを起こしている例です。
JavaScript
let num = 10;
if(num === 10) {
let isTen = true;
}
console.log(isTen); // エラー(isTen is not defined)
変数isTenはif文の { } の中で宣言されている変数であるため、その外からはアクセスできません。
次のように書き換えると、変数にアクセスできるようになります。
JavaScript
let num = 10;
if(num === 10) {
let isTen = true;
console.log(isTen); // true
}
また、『変数を参照するとは?』の章でも紹介しましたが、下のように意図的にブロックスコープを利用することも可能です。
JavaScript
{
let greeting = "Hello, world!";
}
console.log(greeting); // ブロックスコープの外なのでエラーになる
別の場所から変数を参照されると困るような場合は、プログラム処理全体を { } で囲んでおくことで、意図しない変数の書き換えを防ぐことが可能です。
当然ですが、ブロックスコープ内からは問題なく変数を参照できます▼
JavaScript
{
let greeting = "Hello, world!";
console.log(greeting); // Hello, world!
}
POINT!
- ・ブロックスコープは、{ }(波括弧)で囲まれた範囲が有効範囲となる!
- ・JavaScriptの場合、if文の処理などでブロックスコープが発生する!
- ・意図的にブロックスコープを作って利用することも可能!
スコープの入れ子
プログラムを書いていると、複数のスコープが複雑に影響し合うケースも起こります。
たとえば関数の中で条件分岐を行いたい場合、関数を宣言した時点でのスコープが発生し、関数の中のif文でさらにスコープが発生することになります。
こうのようなケースでは、ネストされている方のスコープの方が範囲が狭いことに注意が必要です。
例として、下のプログラムで確認してみましょう。
JavaScript
function test(abc) {
let num1 = 10;
let num2 = 15;
if(num1 % 2 === 0) {
let isEvenNumber = true;
console.log(num1); // 参照可能 ->10
} else {
let isEvenNumber = false;
}
console.log(isEvenNumber); // ブロックスコープの外なのでエラー
}
test();
上の例では、大元のスコープの管理下にあるnum1は関数内であれば参照できるのでエラーにはなりません。
一方、isEvenNumberはif文のブロックスコープ内のみが有効範囲となるため、関数の中であっても参照できずにエラーとなってしまいます。
変数を参照できないエラーが起こった場合、変数がちゃんと宣言されているかどうかだけでなく、有効なスコープの範囲内で宣言されているかどうかも合わせて確認すると良いと思います。
POINT!
- ・関数内の処理などでは、スコープがネスト状態になる場合もあり得る!
- ・ネストされたスコープの方が有効範囲が狭い!
- ・変数の参照エラーが起こった時は、スコープの有効範囲を確認してみよう!