🧊

forループの中でsetTimeoutしたらiはどうなるか

この手の話題は記事タイトルが本当につけにくいw

今回も備忘メモです。

for(var i = 0; i < 3; i++) {
    setTimeout(function(){ console.log(i); });
}

このコード、実行するとどうなるでしょう?

こうなる

for(var i = 0; i < 3; i++) {
    setTimeout(function(){ console.log(i); }); // 3 が3回
}

思ってたのとちがう!

こうすればOK

for(var i = 0; i < 3; i++) {
  (function(local){ // とじこめる
    setTimeout(function(){ console.log(local); });
  }(i)); // とじこめる!
}

すごーくざっくりした理解ですが、

  • JavaScriptはシングルスレッド
  • setTimeoutを使うと、擬似的に実行軸をズラして非同期にできる
  • その結果、本流のforループとsetTimeoutの先の実行タイミングが分離しちゃう
  • よって、本流が即まわりきって i は 3 になり、setTimeout側からは 3 しか取れない
  • それが困るならsetTimeout側の処理へその時点の i を渡す必要がある
  • というか、ループ用の変数 i それ以外を使えば良い
  • コメントで頂いたように外の変数を都度インクリメントしてもいいし、上の例みたく1クッション用意してもいい

なにか間違ってたら教えてください。

コメントで頂いた通り、単にスコープ外なので想定してる動作にはならんよね、というのが本質です。
長々とすみません!