okinawa

IT勉強メモ

for文でvarを使うと危険

参考

JavaScriptの変数宣言はletにすべきか 『入門JavaScriptプログラミング』から解説:CodeZine(コードジン)

基本

varは関数スコープ。同じ関数ないなあらスコープ外からでも参照可能。

letはブロックスコープ。すこーぷ内からのみ参照可能。

letを使いましょう。

letでfor文

下記の部分をvar i = 0;にしたら上手く行かなかったのでメモ。

for (let i = 0; i < link.length; i++) {}

コメントの中に説明を全部書いてしまった。

JavaScript

  /** for文を var i = 0;にするとだめな理由
   * 前提:varは関数すこーぷ。
   * 前提2:for文は i = 3になった時点でループを抜ける。
   * 前提3:var i = 0;は無名関数のスコープ外で宣言されている。
   * 前提4:iをスコープ外である無名関数の中で使っている link[i].classList.addのところ
   * しかし、varだとループを抜けてスコープ外に出てもi = 3が保持され続ける。
   * だから、イベント発火して、link[i].classList.add('visited');のところで
   * i[3]になってしまい、配列の範囲外エラーが出てしまう。
   * デバッグモードでiの値を見てみるとわかる。
   * */ 
  for (var i = 0; i < link.length; i++) {
    // 各ボタンをイベントリスナーに登録
    link[i].addEventListener('click', function (event) {
      event.preventDefault();

      // visitedクラスを付与
      link[i].classList.add('visited');
    });
  }
});

ちなみにaddEventListenerの中身は、for文で回転中には実行されない。 イベント発火した時に実行される。 なので、for文ではイベント登録がされるだけ。

html

            <p><a class="link" href="#">click1!</a></p>
            <p><a class="link" href="#">click2!</a></p>
            <p><a class="link" href="#">click3!</a></p>

CSS

a {
  color: blue;
}

/* click済みの所を紫にする */
.visited {
  color: purple;
}

どうしてもvarでfor文したいなら

即時関数を使います。

参考

qiita.com

window.addEventListener('load', function () {
  // 複数のlinkクラスを配列で取得する
  const link = document.getElementsByClassName('link');

  for (var i = 0; i < link.length; i++) {
    // 各ボタンをイベントリスナーに登録
    (function () {
      var x = i;
      link[x].addEventListener('click', function (event) {
      
        // visitedクラスを付与
        link[x].classList.add('visited');
        event.preventDefault();
      });
    })();
  }
});

正直意味がわからないけどこれで上手くいく。

なぜ x = i; するのだろうか。

i がスコープ外とはいえ、for文回している最中なら普通に012と増えていくのを参照できそうな気がするんだけど。

そしてもうIE対応はやめて!!!

頼む!!!