LoginSignup
1
1

はじめに

JavaScriptでは、varを使ったforループと非同期関数setTimeoutを組み合わせると予期しない動作を引き起こすことがあります。次のコードを見てください:

for (var i = 0; i < 5; i++) {
    setTimeout(() => console.log(i), 1000);
}

期待される動作
このコードは1秒の遅延で0から4の数字をログに出力するはずです。

実際の動作
5が5回ログに出力されます。

バグを見つけられますか?どうすれば解決できますか?

バグの理解

このバグは、varが関数スコープを持っているため、すべての反復で同じi変数が共有されることに起因します。ループが終了するまでにsetTimeoutコールバックが実行され、iは5になっています。

解決策: letを使用する

ECMAScript 2015(ES6)で導入されたletはブロックスコープを持ち、各反復ごとに新しいバインディングを作成します:

for (let i = 0; i < 5; i++) {
    setTimeout(() => console.log(i), 1000);
}

letがバグを解決する方法

  • ブロックスコープ:各ループ反復は自身のiを取得し、各setTimeoutコールバックに正しい値を保持します。

歴史的背景

  • var:JavaScriptの初期から利用可能な関数スコープ。
  • let:ES6(2015)で導入されたブロックスコープ。
  • const:再代入されない変数に使用され、letと同様にブロックスコープを持つ。

違い

  • var宣言はホイスティングされ、undefinedで初期化されます。
  • letconst宣言はブロックスコープであり、ステートメントが評価されるまで初期化されません。

詳細については、MDNのvarlet、およびconstのドキュメントを参照してください。

解決策: IIFEとクロージャーを使用する

即時関数呼び出し式(IIFE)は新しい関数スコープを作成し、各反復の現在のi値を保持します。このアプローチはクロージャーを利用して正しい変数値をキャプチャします:

for (var i = 0; i < 5; i++) {
    (function(i) {
        setTimeout(() => console.log(i), 1000);
    })(i);
}

IIFEとクロージャーがバグを解決する方法

  • 関数スコープ:各IIFE呼び出しは新しい関数スコープを作成し、現在のiをキャプチャします。

歴史的背景

IIFEは早期のJavaScriptバージョンからスコープを作成し、変数のライフタイムを管理するために使用されてきました。クロージャーはJavaScriptの基本的な概念であり、関数が囲むスコープから変数をキャプチャして保持することができます。これらのパターンは、letconstが利用できないES5やそれ以前のバージョンで特に有用です。

詳細については、MDNのIIFEおよびクロージャーのドキュメントを参照してください。

解決策: console.log.bindを使用する

もう一つの解決策は、現在のi値をキャプチャするバウンド関数を作成するためにconsole.log.bindを使用する方法です:

for (var i = 0; i < 5; i++) {
    setTimeout(console.log.bind(console, i), 1000);
}

console.log.bindがバグを解決する方法

  • バウンド関数bindthisconsoleに設定し、最初の引数を現在のi値に固定した新しい関数を作成します。これにより、各setTimeoutコールバックが正しいi値を出力します。

歴史的背景

Function.prototype.bindメソッドはECMAScript 5(ES5)で導入されました。初期引数が固定された関数を簡単に作成できるため、スコープを管理し、非同期コールバック内で変数値を保持するための強力なツールです。

詳細については、MDNのbindのドキュメントを参照してください。

結論

変数スコープを理解することは、JavaScriptを習得する上で重要です。setTimeoutを含むよくある面接質問を解決する3つの方法を探りました:

  1. ブロックスコープを提供するletを使用する
  2. 正しい変数値をキャプチャするためにIIFEとクロージャーを使用する
  3. バウンド関数を作成するためにconsole.log.bindを使用する

これらの解決策を試して、コメントで代替方法を共有してください!

1
1
0

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
1
1