1

I have previously posted on SO:

How would you set the following loop to log like below?

The answer was to change var to let.

I am currently learning javascript after having studied python for a few months. I just wanted to see where my analysis is going wrong as I am struggling to apply the concept of block scope and function scope here.

Here is the original code snippet:

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

What I do not understand is, if I delete the setTimeout function bit and end up with this:

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

The output changes from

5
5
5
5
5

to

0
1
2
3
4

which was what I thought it should initially do. I don't understand why in the first case the need to use let i was necessary but in the second case it works fine with var.

Another point of confusion is that, if you take the first code snippet, with the setTimeout function, the value of the final i printed is 5. This does not make sense considering our initial for loop was only supposed to run till i<5.

The last point I am struggling with is that even if i was allowed to take on the value of 5, it seems the action (printing i) is done after the loop? I am saying this because i starts off at 0, and increases in value iteratively, here we are printing the final value of i 5 times. This must mean the computer has gone through the iteration before and then decides to do the action using the final value of i but 5 times?

Essentially I thought it goes as follows, we create a variable i using var, we say that as long as i is less than 5, do something, after doing something increase i by 1 and repeat. Instead what it looks like from the first codes output is, create a variable i using var, i increases by 1 till i equals 5, do the action as many times as the number of iterations.

Sorry if this question is not coherent but I can't seem to apply the concepts of function scope and block scope here, which I feel is the key issue. Can someone please elaborate on this particular example?

Vishal Jain
  • 443
  • 4
  • 17
  • If possible I would have liked someone to address the specific queries I had? Is there any service on this website that offers that? – Vishal Jain Oct 17 '19 at 16:38
  • *"I don't understand why in the first case the need to use `let i` was necessary but in the second case it works fine with `var`."* Because without the `setTimeout`, you're using `i` immediately, so you see its current value. With `setTimeout`, you're seeing it's value **later**, when that code runs. With `let`, in contrast, there's a **different** `i` for each loop iteration (literally a different variable). – T.J. Crowder Oct 17 '19 at 16:38
  • *"This does not make sense considering our initial for loop was only supposed to run till `i<5`."* Because after the last loop iteration when `i` is `4`, you have `i++`, which makes `i` `5`. Then the comparison `i < 5` is done, is false, and so the loop ends. But that's when `i` already has the value `5`. – T.J. Crowder Oct 17 '19 at 16:38
  • Re your comment *"Is there any service on this website that offers that?"* That's not how SO works, but usually in cases like this after pointing to the duplicate with its answers (which you want to read! :-) ) I try to take a minute to post comments (as I did above, but I was still typing when you commented) to help the person asking see how the answers relate to their specific question. *(And I get why SO works this way, though sometimes I really, really want to post an answer instead. :-) )* – T.J. Crowder Oct 17 '19 at 16:40
  • *"Sorry if this question is not coherent..."* Nothing incoherent about the question in my view! Very clearly asked. – T.J. Crowder Oct 17 '19 at 16:41
  • You may find [this answer](https://stackoverflow.com/questions/58101855/is-there-no-difference-between-let-and-const-inside-for-of-loop-in-javascript-in/58101910#58101910) and [this answer](https://stackoverflow.com/a/40070682/157247) useful as well. Happy coding! – T.J. Crowder Oct 17 '19 at 16:48
  • Thanks for the clarifications, just one final query about this is that, with the `setTimeout` function, you say we are using the value of `i` afters it been through all its iterations. I.e, we have completed the loop. In that case I would expect the code to run `setTimeout` would only occur once after the loop has been executed completely and the next bit of code is run with `i` = 5. Instead we see that the code is run 5 times with 'i=5' each time? This makes little sense to me as it means we go through the entire loop and then run the final bit of code 5 times for no apparent reason? – Vishal Jain Oct 17 '19 at 16:50
  • Yeah, that was poor phrasing on my part. :-) The calls to *`setTimeout`* are synchronous; it's the calls to the callback function you're passing into `setTimeout` that happen later. Another aspect of this is that each loop iteration creates a new callback function, so you end up with five callback functions. With `var`, all five callbacks close over the same `i` so you see `i=5` five times. With `let`, each of the callbacks closes over a *different* `i` (the one that was present in the loop iteration when that callback was created), so you get 0, 1, ... – T.J. Crowder Oct 17 '19 at 16:59
  • I'm not 100% sure that answered your question in that comment. Basically, you get the code within the callbacks running five times because there were five calls to `setTimeout` scheduling the callbacks. And then the reason for the `var`/`let` difference is what those callbacks close over. (BTW: This is **not** a simple part of JavaScript, so it's no surprise people don't get it instantly.) – T.J. Crowder Oct 17 '19 at 17:01
  • 1
    This is what I was looking for, thanks it makes more sense now. – Vishal Jain Oct 17 '19 at 17:09
  • Happy to help. I'm writing up something I'll post in a moment that explains it more throughly, just a sec. – T.J. Crowder Oct 17 '19 at 17:11
  • 1
    Here's that deeper explanation: https://pastebin.com/rYRPfzgE BTW, I cover this in [my book](https://www.amazon.com/JavaScript-Toys-T-J-Crowder/dp/1119367956/) coming out early next year. Happy coding! – T.J. Crowder Oct 17 '19 at 17:17

0 Answers0