LoginSignup
5
4

More than 3 years have passed since last update.

setTimeoutをloopしたときのvarとletの挙動の違いについて

Last updated at Posted at 2020-04-22

varのとき

js
var messages = ["foo", "bar", "hoge"];

for (var i = 0; i < messages.length; i++) {
  setTimeout(function() {
    console.log(messages[i], i);
  }, i * 100);
}

// undefined 3
// undefined 3
// undefined 3

letのとき

js
const messages = ["foo", "bar", "hoge"];

for (let i = 0; i < messages.length; i++) {
  setTimeout(function() {
    console.log(messages[i]);
  }, i * 100);
}

// 'foo'
// 'bar'
// 'hoge'

挙動の違いについて

varを使用したほうの問題点は、iの値がすべて「3」になっている点です。
これには理由が2つあります、

1. varはブロックスコープを無視する

varはブロックスコープを無視して、もっとも近い関数スコープの直下に宣言部分が巻き上げられます。今回のfor文でも同様に、loop内でスコープを持っておらず、毎度iの値を上書きしてしまっていることになります。

2. for文の処理が完了後にcallback関数が発火される。

setTimeout内の関数は0ms,100ms,200ms後に発火するようにcallbackタスクキュー内に入り、その後に関数が発火します。関数が発火するタイミングでは、varの値がloop後の値になってしまい、結果iの値が3の状態ですべての関数が発火するので、undefinedが返ることになる。

letでは問題ない理由

letの場合、ブロックスコープを持ちます。for文でループが回るたびにスコープをもつことになるため、callback関数が参照するiの値もsetTimeoutで登録されたときの値になります。結果、意図した挙動になります。

5
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4