Skip to content

Instantly share code, notes, and snippets.

@chris-campbell
Last active November 29, 2022 15:41
Show Gist options
  • Save chris-campbell/8c7a38a8923c2befb4ba9a2a7faaaee6 to your computer and use it in GitHub Desktop.
Save chris-campbell/8c7a38a8923c2befb4ba9a2a7faaaee6 to your computer and use it in GitHub Desktop.

Can you tell us why the following Javascript code doesn’t work correctly?

How would you fix it?

Problem

function count() {
    let counter;

    for (counter = 0; counter < 3; counter++) {
        setTimeout(function () {
            console.log('counter value is ' + counter);
        }, 100);
    }
}
count();

Issues

  • The let counter declarations is operating almost as var declaration, its scope is the whole function.
  • Each iteration of the for loop registers a callback that will be evaluated when the for loop exits, this results in the counter value being 3.
  • setTimeout forms a closure for value counter and since counter is defined on a function level rather than on the block level of the for loop setTimeout doesn't get the appropriate closure counter value.

Fix

  • Move the counter declaration to the for loop, since let is block-scoped, each iteration of it will have its own counter and it will provide the closure needed to setTimeout to get desired results.
  • OR
  • Move setTimeout into it's own function and invoke it immediately in the for loop, This will make closure containing the required values

Solution 1

function count() {
    for (let counter = 0; counter < 3; counter++) {
        setTimeout(function () {
            console.log('counter value is ' + counter);
        }, 100);
    }
}

count();

Solution 2

const timeout = (counter) => {
     setTimeout(function () {
            console.log('counter value is ' + counter);
      }, 100);
}

function count() {
    for (let counter = 0; counter < 3; counter++) {
       timeout(counter);
    }
}

count();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment