変数の「スコープ」は正しく理解しないと、エラーにならないエラーが起きて相当こまることになっちゃいます。
実際、デバッグしてエラーはないのに期待している効果が得られず、原因を見つけるのに予想以上に時間を消費してしまったことがあるんです。
そんなわけでおさらい。
JavaScriptのスコープは大きく分けて2つです。
- グローバルスコープ
- 関数スコープ(ローカルスコープ)
その名の通り関数の外、トップレベルコードのスコープです。
これは分かりやすいですね。
関数の外で変数を宣言しておけば、どこでも使えちゃうってわけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 | //グローバル変数 var x = 0; function f(){ x = 2; print(x); } function f2(){ print(x); x = 3; print(x); } |
結果はこんな感じ。
1 2 3 | 2 2 3 |
こちらも名前の通り関数の中で宣言した変数ですね。
注意点は、関数内の変数は宣言した行とは関係なく、その関数内で有効ってこと。
だから関数内の変数は関数の冒頭にまとめておくようにしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 | function f(){ //関数変数 var x = 2; print(x); } function f2(){ //関数変数 print(x); //関数変数 var x = 3; print(x); } |
結果はこんな感じ。
1 2 3 | 2 undefined 3 |
注意点として、ブロックスコープはありません。
例えば、以下。
1 2 3 4 5 6 7 8 9 10 11 | //グローバル変数 var X = 5; //ブロックスコープを期待してこう書く { var X = 3; print(x); } //これに5が入ってることを期待すると間違う print(x); |
結果はどちらも3が入ってます。
1 2 | 3 3 |
ブロックスコープがないので、
実際はグローバル変数を使い回しているんです。
実はJavaScriptの独自拡張にブロックスコープが使える「let」というのがあるらしいのですが、私は使っていません。なんかややこしくなりそうで^^;
もうひとつオマケ。
JavaScriptの関数は入れ子に宣言できます。
そのとき、内側の関数内で参照している変数が見つからなければ、
そのひとつ外側の関数に向かって変数名を探しにいきます♪
でもって、最終的にグローバル変数を参照することになりますね〜。