+ 12
I need help from js experts
How does this code print "3, 3, 3" and not "0, 1, 2"? It works when you change the "var" with "let" but I still cant see the difference. Pls some one explain! https://code.sololearn.com/WdSI3g7iRyQk/?ref=app
20 Réponses
+ 15
[Part 1]
This is a good question, it gave me hard times when I faced this doubt.
To understand this completely we first need to make sure we understand these 2 concepts.
1. How Scopes work differently for "let" & "var"?
2. How setTimeout() method works?
To understand this we need to know the concept of "event loops" in JavaScript.
I ll write a 4 part answer below, this being the first part.
2nd part - let vs var
3rd part - quick intro on asynchronous operations using event loops
4th part - binding it all together to finally answer your question
[Continued in Part 2]
+ 14
[Part 2] : Let Vs Var
Here is a code going through the 4 differences between the 2
https://code.sololearn.com/WdGAFeNRAe9M/#js
The important conclusion to take from above code is the first difference.
var is function scoped, which means local scope of variables created by var keyword is only effective inside function blocks. Therefore the variables declared using var inside for loop block will be in global scope.
for(var i =0; ; ){ }
is same as
var i =0;
for(i =0; ;){}
whereas let is block scoped, which means any curly braces {} can create a local scope for variables declared using let keyword. It doesnt matter where the curly braces are coming from it ll be same for all i.e
- function(){}
- for(;;){}
- if(){}
- or just {}
[Continued in Part 3]
+ 13
var is global variable, for timer functions that going to be executed later, the functions would use the var i which is the last iterated value, since it is overwritten to the last value, before the timer functions run.
To prove i is a global variable, I take your code
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
i = 1000; // add another last value here.
This code would output
1000
1000
1000
1000
https://code.sololearn.com/WG2AX2GfqWZG/?ref=app
+ 13
[Part 4] : Grand Finale
We know now that how let and var behaves differently
var -> creates global scope variables inside for(;;){}
let -> creates local scope variables inside for(;;){}
we also know that async codes are skipped and executed after synchronous codes in next event loops,
so all the code inside the setTimeout() block will be executed after 1 second when we have completed the other code i.e looping through the for loop 3 times.
Now we can have an interpretation of how JS-Engine sees the code, which is demonstrated here in this code.
https://code.sololearn.com/Wh2ENDDNg9V5/?ref=app
Important Note:
Although this will complicate the answer unnecessarily but I would like to highlight that the inner working of let to create a local scope is merely a hack. Unlike other languages where rather than declaring a variable once and incrementing it, let variables are declared again and again.
https://stackoverflow.com/questions/16473350/let-keyword-in-the-for-loophow
+ 12
let i defines i in block scope, each iteration is a separated block scope for i, thus you still can get the difference i values in timer functions later.
https://code.sololearn.com/WXdVtq9sS5m0/?ref=app
For more information https://wesbos.com/for-of-es6/
+ 11
[Part 3] : setTimeout()
In Javascript at the heart of the JS engine there is a mighty loop called "Event Loop". The basic concept behind event loop is to make all the time taking operations as asynchronous(aka async).
setTimeout() is also an async method.
so while running a JS code whenever an async method is encountered then the JS engine skips that code and mark it as "I ll run you later on when I have been through all the code && you are done(i.e some event is fired)".
I know I did a terrible job in explaining specially the meaning of Asynchronous, but I ll highly suggest to go through this article for a better understanding.
https://hackernoon.com/understanding-js-the-event-loop-959beae3ac40
Back to our code, so every time setTimeout is encountered inside for loop, it is just being ignored until we reach the end of the code. In later event loops after 1sec JS engine realizes that "Oh the setTimeout part is still pending 3 times.
so it executes the console.log(i) 3 times
[Continued in Part 4]
+ 7
Please read the reference materials shared by everything.js every day, especially the concept of scope, closures and event loop.
https://www.sololearn.com/post/91896/?ref=app
+ 7
Awesome answers!... but if you still want to get deeper into var, let and const, you could check out my blog.
https://code.sololearn.com/WdauYjg8rOiF/?ref=app
+ 6
interesting ...
Biraj
+ 5
Morpheus thank you very much! That was very helpful.
+ 4
Asmerom Estifanos
In the code shared by Alfa, the timeout period is fixed 1 second, so all console.log(i) will happen after 1 sec but we can make it variable to give output in 1 second gaps like this.
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, (i + 1) * 1000);
}
Note that even if you use var here, the behavior will still be the same but we ll just get three '3' in 1 sec delay each.
Btw, i encountered this problem presented by you myself when I was trying to do what you were trying to do in this code. It was an attempt to make timed presentation out of html.
https://code.sololearn.com/WGGbx9i3f01C/?ref=app
+ 4
Thanks a lot Morpheus for taking your time...That was very helpful!!!
+ 4
Biraj no need to wrap the setTimout function inside an IIFE you can just pass the i index as an argument to the setTimeout function for later use:
for (var i = 0; i < 3; i++){
setTimeout(function(i) {
console.log(i);
}, 1000, i);
}
+ 4
Morpheus you have really broken down the whole question..
Thanks, it was very valuable info.
+ 2
Morpheus I have one tiny question, how can we output 0,1 & 2 every one second? I mean put a one second gap between the three outputs?
+ 2
Biraj my pleasure brother.
+ 1
This is a good question, it gave me hard times when I faced this doubt.
To understand this completely we first need to make sure we understand these 2 concepts.
1. How Scopes work differently for "let" & "var"?
2. How setTimeout() method works?
To understand this we need to know the concept of "event loops" in JavaScript.
I ll write a 4 part answer below, this being the first part.
2nd part - let vs var
3rd part - quick intro on asynchronous operations using event loops
4th part - binding it all together to finally answer your question
Next...
0
I don't know if I have done that correctly, but I made a demonstation of what kind of happens behind the scenes, I will post it here since it may be helpful:
https://code.sololearn.com/WgwRxAY2IHNq/?ref=app