白猫のメモ帳

C#とかJavaとかJavaScriptとかHTMLとか機械学習とか。

javascriptのスコープって何?

前回の続き。
続きものなのにこの間の空きかたたるや…。

まぁいいか。

スコープとは変数の有効範囲ということを書いた。
今回はこれについてちょっと掘り下げてみる。

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好きな私は分かっていても途中で宣言してしまうのだけれど。