クロージャが効かないバグになりそうなJavaScriptの仕様

2016 年 11 月 10 日 by 山平

今年度入社の新人がJavaScriptの勉強をしていました。
少し手ほどきした、という話は以前にしました。

で、その後自由に手を動かしてもらっていたのですが、ひょいとのぞいたときに「んん~?」となったことがあったので記録しておこうと思います。

問題(ではないのですが)のサイトはこちら

ローカル変数は関数全体で有効だから同じ関数内なら変数宣言より前のコードからアクセスできるΣ(・ω・ノ)ノ!
→「ホイスティング(巻き上げ)」と呼びます

JavaScript:
  1. var scope = "Global";
  2. function getValue() {
  3. console.log(scope);    // undefined
  4. var scope = "Local";
  5. return scope;
  6. }
  7. console.log(getValue());    // "Local"
  8. console.log(scope);    // "Global"

仮引数もローカル変数……同名の変数でも別物として扱います

JavaScript:
  1. var n = 0;
  2. function hoge(n){
  3. n++;
  4. return n;
  5. }
  6. console.log(hoge(n));    // 1(仮引数(ローカル変数)を参照)
  7. console.log(n);        // 0(グローバル変数を参照)

これ、クロージャ効かないんでしょうか?
試しに少し書き換えて動作を確認します。

「ホイスティング(巻き上げ)」の確認

JavaScript:
  1. var scope = "Global";
  2. function getValue() {
  3. console.log(scope);    // undefined => "Global"に変わった!
  4. //var scope = "Local"; // ★ここをコメントアウト
  5. return scope;
  6. }
  7. console.log(getValue());    // "Local" => "Global"に変わった!
  8. console.log(scope);    // "Global" => "Global"のまま

「仮引数もローカル変数」の確認

JavaScript:
  1. var n = 0;
  2. function hoge( /* n */){  // ★仮引数をコメントアウト
  3. n++;
  4. return n;
  5. }
  6. console.log(hoge(n));    // 1(仮引数(ローカル変数)を参照)
  7. console.log(n);        // 0(グローバル変数を参照)  => 1に変わった!

はい、この書き方だと、クロージャとして動きました。
私個人としては、「ホイスティング(巻き上げ)」「仮引数もローカル変数」よりもクロージャの方が身近なので、これはクロージャが効かなくなる仕様だ、と思いました。
逆にクロージャに不慣れな方は、変数に期待しない値が入ってしまう仕様だ、と感じるかもしれないです。

新人教育といいつつ、自身のためにもよい勉強になりました。

タグ:

TrackBack