question about scope, closures and Let variables [duplicate] - javascript

This question already has answers here:
setTimeout in for-loop does not print consecutive values [duplicate]
(10 answers)
JavaScript closure inside loops – simple practical example
(44 answers)
What is the difference between "let" and "var"?
(39 answers)
Closed 1 year ago.
I am reading about closures, and I found these small exercises that I solved by chance, but I don't understand why they work.
The exercise is :
for (var i = 0; i < 3; i++) {
setTimeout(function log() {
console.log(i); // What is logged?
}, 1000);
}
I get that 3 will be printed 3 times because the value captured by log() when the for() ends.
Additionally, it was asked how to fix it for the console to print 0,1,2, and I found (by chance, to be honest), that it works by doing :
for ( let i =0 ...
But I guess because Let is block scoped, but i don't really know how to explain it in simple words.

The variables defined with let are blocked scope which means once you go out of the bracket it loses its value and if you try to access it will throw you an error. So, when the for is running the, i present in the console.log() will store the value for it like 0,1,etc.
whereas in the var part the var will be stored in memory and when the timeout is about to expire it will access the variable i in the memory and print whatever is there for that variable at that time.

Related

Javascript for loop variable scope [duplicate]

This question already has answers here:
Explanation of `let` and block scoping with for loops
(5 answers)
JavaScript closure inside loops – simple practical example
(44 answers)
let keyword in the for loop
(3 answers)
JavaScript: Understanding let scope inside for loop [duplicate]
(3 answers)
Closed 6 months ago.
This question is inspired by a very famous trick interview question for javascript closures, however I am more interested into another aspect of it. The code goes as follows:
let i
for (i = 0; i < 3; i++) {
setTimeout(function log() {
console.log(i); // What is logged?
}, 1000);
}
The answer is 3 3 3, and (I think) I know the explanation, each callback function can access the same i variable, by the time they are executed its value is 3.
When we write let inside for loop like this:
for (let i = 0; i < 3; i++) {
setTimeout(function log() {
console.log(i); // What is logged?
}, 1000);
}
Now we get 0 1 2. Ok, here the explanation is that when declared this way, i is scoped to this loop, not available outside, and each iteration has its copy of i.
The part that bugs me: it does not seem to be a different variable in each step. If we change i in a first step, it will be changed for other steps.
for (let i = 0; i < 3; i++) {
setTimeout(function log() {
console.log(i); // What is logged?
}, 1000);
if (i === 0) i ++
}
The result now is 1 2, skipped one step.
So I see two possible explanations for this, but I cannot confirm this anywhere.
Closures work differently for block-scoped and function or global scoped variable
After each step of the loop, the current state of the variable declared in a loop is copied to a new variable for the next step of the loop
???
Note: Please let's not focus on why values are 3 3 3 instead of 2 2 2, let's not go into event loop with setTimeout etc. unless relevant to the answer. I feel like closures and variable scopes will be most relevant here.

Event Listener with Parameter created Dynamically [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
let keyword in the for loop
(3 answers)
What is the difference between "let" and "var"?
(39 answers)
Closed 2 years ago.
I am dynamically creating a series of buttons using a for loop and adding an Event Listener to them as follows (I have excluded several lines of code for simplicity). However, upon using any of the buttons after creation, the parameter "i" always corresponds to the value "i" had when it exited the for loop. I have seen numerous proposed solutions online, but none of them are actually working.
for (var i = 0; i < size; i++) {
button.addEventListener('click', () => this.Purchase(i))
}
You should use let i = 0 instead of var i = 0 in order to have the i variable be scoped to the loop. With var, i is scoped to the innermost function, which means it constantly gets overwritten. See here for more info.

Query about closures and difference between var and let [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
How do JavaScript closures work?
(86 answers)
Closed 3 years ago.
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?

Why incrementor is printing 3 even condition is checking for less then 3? [duplicate]

This question already has answers here:
What is the difference between "let" and "var"?
(39 answers)
JavaScript closure inside loops – simple practical example
(44 answers)
How do JavaScript closures work?
(86 answers)
Closed 4 years ago.
for below code output will print "3" for 3 times, i.e updates same variable for 3 times
for(var k=0;k<3;k++){
setTimeout(()=>{
console.log(k)
},1000)
}
similarly if i use let instead of var 1,2,3
for(var k=0;k<3;k++){
setTimeout(()=>{
console.log(k)
},1000)
}
i know why it prints 0,1,2 as i is different every time. i'm just wondering why its printing 3 in case of var as condition is to checking for less then 3?
The above result is because, var defines variable globally, or locally to an entire function regardless of block scope.
let creates a variable declaration for each loop which is block level declaration. So basically it creates a scope within { }.
If you want to print using var keyword use self invoked functions :
for(var k=0;k<3;k++){
(function(k){
setTimeout(()=>{
console.log(k)
},1000)
})(k);
}
the function setTimeout will execute after the delay provided. The code execution doesn't stop since the javascript is based on concurrency model and event loop, so the execution continues till the delay provided. which in case, increment the k. Also, the post-increment operator will use the value before iteration. So, for last iteration the value of k is 3, but since we have given a delay, it would print 3 every time.

Looping JS variable doesn't show the correct value inside the function [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Doesn't JavaScript support closures with local variables? [duplicate]
(7 answers)
Closed 8 years ago.
I need to do the following task. But this always alerts only "5" instead of 1,2,3,4 and 5. How can I fix this? Please help.
for(var x=1; x<=5; x++){
something.load(function(result){
alert(x);
});
}
This is due to closure. When the callback is runned, it will alert the variable in its current state (so after the loop).
To fix this, you can create a new closure which'll keep the variable state.
for(var x=1; x<=5; x++){
(function(x) {
something.load(function(result){
alert(x);
});
}(x));
}
For a more complete explanation of Closure, you can refer to this SO question: How do JavaScript closures work?
Or this article by a member of TC39 (EcmaScript standard body) http://www.2ality.com/2013/05/quirk-closures.html

Categories

Resources