0

I'd like to understand the following code:

for (var i=0; i<3; i++){
    setTimeout(() => {
        console.log(i);
    }, 1000);
}
console.log('After the Loop');

Prints After the loop,3,3,3

for (let i=0; i<3; i++){
    setTimeout(() => {
        console.log(i);
    }, 1000);
}
console.log('After the Loop');

Prints After the loop,0,1,2

I know that the events are executed after the main, so the numbers of i appear after After the loop. And letmeans block scope (so iis visible in for-loop only) and varfunction scope (so it should be visible globally here), but I still don't see why the first prints 3,3,3.

Can anyone please provide a resonable explaination?

Thanks!

avermaet
  • 1,543
  • 12
  • 33
  • 1
    In the first example there is only a single variable `i` and all functions refer to that. A single variable can only have a single value at a time. – Felix Kling Nov 04 '19 at 21:27
  • 1
    [How do JavaScript closures work?](https://stackoverflow.com/q/111102/691711) and [let keyword in the for loop](https://stackoverflow.com/a/35812376/691711) – zero298 Nov 04 '19 at 21:29
  • Got it :-) Thanks everyone! – avermaet Nov 04 '19 at 21:34

2 Answers2

3

When you use var, the same i is shared by all the anonymous functions passed to setTimeout(). The timeouts fire a relatively long time after the loop finishes, so by that time the value of the (shared) i is 3.

Pointy
  • 405,095
  • 59
  • 585
  • 614
1

Consider the following examples which show i defined using var and let and how scope is determined at the function and block level.

// "i" defined with "var" within the function scope
function foo() {
    var i;
    for (i = 0; i < 3; i++) {
        setTimeout(() => console.log('foo', i), 250);
    }
    // output: 3 3 3
}

// "i" defined with "let" within the function scope
function bar() {
    let i;
    for (i = 0; i < 3; i++) {
        setTimeout(() => console.log('bar', i), 250);
    }
    // output: 3 3 3
}

// "i" is defined within the block however it gets hoisted up
// to the function scope as this is the behavior of "var"
function baz() {
    for (var i = 0; i < 3; i++) {
        setTimeout(() => console.log('baz', i), 250);
    }
    // output: 3 3 3
}

// "i" is defined within the block and "let" allows "i" to maintain the block scope
function boo() {
    for (let i = 0; i < 3; i++) {
        setTimeout(() => console.log('boo', i), 250);
    }
    // output: 0 1 2
}
wdm
  • 7,121
  • 1
  • 27
  • 29