前回の続き。
続きものなのにこの間の空きかたたるや…。
まぁいいか。
スコープとは変数の有効範囲ということを書いた。
今回はこれについてちょっと掘り下げてみる。
javascriptのスコープは、
・グローバル・スコープ
・ローカル・スコープ
に大きく分けられる。
まず、「グローバル・スコープ」
これはプログラム全体から参照できる変数。
関数の外で宣言すると、グローパル・スコープになる。
関数自体も第一級オブジェクトなので、
グローバルなFunction変数と考えることができる。
そして、「ローカル・スコープ」
これは関数の中からだけ参照できる変数。
関数の外から参照しようとすると"undefined"になる。
var scope = "ぐろーばる"; function func() { var scope = "ろーかる"; alert(scrope); } alert(scrope);
こんな感じで書くと「ろーかる」がアラートされたあとに「ぐろーばる」がアラートされる。
var scope = "ぐろーばる"; function func() { scope = "ろーかる"; alert(scrope); } alert(scrope);
しかし、こう書くと「ろーかる」が2回アラートされる。
これは、2つ目の例では var をつけていないので関数の中で宣言がされず、
関数の外側に変数を探しに行くから。
こんな風に外側のスコープまで変数を探しに行く仕組みを「スコープチェーン」という。
関数がネストしている場合には、順番の外側のスコープを探していき、グローバルスコープでも見つからないと"undefined"になる。
また、もう一つ重要な点として、javascriptにはブロックスコープがない。
for (int i = 0; i < 100; i++) { // なんかする } System.out.println(i);
javaではこんなソースを書くと、iが宣言されていないということで怒られてしまうが、
for (var i = 0; i < 100; i++) { // なんかする } alert(i);
javascriptではさらっと「100」とアラートされる。
つまり、ループやifなどのブロックなどにはスコープが存在しないということだ。
さらにもうひとつ、関数内がスコープということで、関数内では宣言前に参照ができるという仕組みがある。
これを「ホイスティング」という。
つまり、関数の途中で変数を宣言しても、実質的には関数の先頭ですべての変数を宣言していることになる、
var scope = "ぐろーばる"; function func() { alert(scrope); var scope = "ろーかる"; }
これは
var scope = "ぐろーばる"; function func() { var scope; alert(scrope); scope = "ろーかる"; }
こうなるので、"undefined"になる。
注意していないと思わぬ罠にはまることになる。
というわけで、関数の先頭ですべての変数を宣言した方がいいという話もある。
とはいえ、java好きな私は分かっていても途中で宣言してしまうのだけれど。