Two similar for loop outputs different value [duplicate] - javascript

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 2 years ago.
I can't figure out the output of the following two loops. The only difference I notice is that the former use var and assigns a global scope and later create a local scope using const.
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
the output is 3 3 3 and 0 1 2.
According to my shallow knowledge, the first loop has to output 0 1 2.
If I print the value of i in the first loop.
for (var i = 0; i < 3; i++) {
console.log(i);
setTimeout(() => console.log(i), 1);
}
the output printed in the console by first console.log(i) is 0 1 2. While in the one wrapped within setTimeout vary.
Why?

var gets hoisted into the global scope, so when setTimeout is called it logs out whatever the value of i is when it is called, which would be 3 as the for loop has set i to 3 on its last iteration. Whereas let is scoped to the for loop and closes over the value of i on each iteration, thus printing 0 1 2.

Related

I get strange output when i use var keyword in for loop with setTimeOut inside [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 2 years ago.
I have this code.
for (var i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
I don't understand the output from this lines of code:
The output in the console is number 6,and it says that is repeated five times.
If i use the let keyword for "i" then i get the output that i expect,
1,2,3,4,5 after one second
Why is that ?
var has scoping issues and that's why let was introduced.
In your for loop you are defining i, but actually it's stuck to the global scope, and after 1 second, the for loop would actually be done, and when the setTimeout callback is fired, i would have already reached 6 and it's read from the global scope.
In a nutshell, because i is stuck to the upper scope of for, each iteration modifies the calue of i and doesn't create another i.
If you change var to let, the issue is resolved.
setTimeout is async hence will execute after the loop is done, that s why you have i=6, put it in a self invoking function to retain the value of i or use let instead of var in your loop
for (var i = 1; i <= 5; i++) {
((i) => setTimeout(function() {
console.log(i);
}, 1000))(i)
}
for (let i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}

(javaScript) value in and out of 'for loop'

I am a beginner with javaSCript and just wondering why the results are different when it's called "inside" the loop and "outside" the loop.
for (var i = 0; i < 5; i++) {
console.log(i);
// prints 0 1 2 3 4
}
console.log(i);
// prints 0 1 2 3 4 5
Because the for looping steps is :
1 - define a variable,
2 - check the condition,
3 - run the code inside the loop,
4 - and increase the loop variable value by 1 ,
But! After defining the variable and After the first loop, it will ignore the first argument var i = 0 and it will increment the loop variable by 1, and check the condition, why? Because in the for looping, the last thing to do is increase the loop variable by 1,
So the last loop will increase the loop variable by 1 and check the condition ,
Simply: the variable has changed through the loop to 5 because after the first loop it will increase the variable by 1 and checking the condition
I hope my answer will be useful to you!
That's how var in JS works and also that's how for loops in all languages work.
When you declare a variable using var keyword it is hoisted to the function scope, or global if not inside a function. This lets you access var outside of the for loop scope. Try changing var to let and see what happens.
Secondly, you don't see 5 printed in the for-loop because of your condition i < 5. i++ causes 'i' to go from 4 to 5 which breaks the for-loop conditions and the 'i' is not printed.
Lastly console.log(i) outside the for-loop should just print 5 because that is the value of i at that point and not
console.log(i);
// prints 0 1 2 3 4 5
// should print 5
Inside the loop it logs the numbers from 0 to 4. The last i++ sets i to 5, and the loop stops because i < 5 is no longer true. Then the console.log(i) after the loop logs this value.
During the loop execution, the condition i < 5 fails for "5<5" but still the value of i here becomes '5' which is executed outside of the loop
for (var i = 0; i < 5; i++) {
console.log("inside loop: " + i);
// prints 0 1 2 3 4
}
console.log("outside loop: " + i);
// prints just 5

Can't understand how this javascript code control flow? [duplicate]

This question already has answers here:
How do JavaScript closures work?
(86 answers)
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 3 years ago.
This is the code of which i am not able to understand the flow of and also how the value of i persist even after the for loop ends.
var printNumTwo;
for (let i = 0; i < 5; i++) {
if (i === 2) {
console.log("now");
printNumTwo = function() {
console.log("inside");
return i;
};
console.log(i);
}
console.log(i);
}
console.log(printNumTwo());
The output of the program is
0
1
now
2
2
3
4
inside
2
reason of this behavior is Closures
A closure gives you access to an outer function’s scope from an inner
function. In JavaScript, closures are created every time a function is
created, at function creation time. mozilla doc
var printNumTwo;
for (let i = 0; i < 5; i++) {
if (i === 2) {
console.log("now");
printNumTwo = function() {
console.log("inside");
return i;
};
console.log(i);
}
console.log(i);
}
console.log('now calling printNumTwo()')
let s=printNumTwo();
console.log('now printing return value of printNumTwo()')
console.log('retrun value of PrintNumTwo is:'+s);

Javascript closure inside for loops [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 5 years ago.
I am in the process of learning JavaScript. While I completely understand that JavaScript does only have function scope and not block scope, I have stumbled accross an example of a for loop in which functions are created completely and I completely ignore why the following example does not work like one would expect it to.
var funcs = [];
for (var i = 0; i < 3; i++) { // let's create 3 functions
funcs[i] = function() { // and store them in funcs
console.log("My value: " + i); // each should log its value.
};
}
for (var j = 0; j < 3; j++) {
funcs[j](); // and now let's run each one to see
}
It outputs this:
My value: 3
My value: 3
My value: 3
And not:
My value: 0
My value: 1
My value: 2
Now I know that the solution would be something like this would be to create a function that returns a function returning the i value which would create a closure for said function.
However, my question is rather, and I have seen a couple of explanations which I don't quite get, why the example does not work in the first place and what is actually happening?
I am unsure how the array func is filled with three keys:
func[0], func[1] and func[2] while the function declaration will always return 3? Why would func[0] even exist in the first place and not only func[3]? It seems to me that there some kind of scope is created in the for loop but only for assigning a key but not for the assignment which I find odd.
Could someone enlighten me? How would a step by step evaluation of the for-loop look like and why?
Thank you very much for your help already!
func[0], func[1] and func[2] while the function declaration will always return 2?
No. func[i] always returns 3, because i is 3 when the function runs.
It seems to me that there some kind of scope is created in the for loop
There isn't (well, there is, but let isn't in play so it isn't used for anything). The scope is defined by the enclosing function. i exists in that scope and gets changed by the for loop.
How would a step by step evaluation of the for-loop look like and why?
var funcs = [];
Create an array
for (var i = 0; i < 3; i++) { // let's create 3 functions
Sets i to 0, 1, 2, 3.
funcs[i] = function() { // and store them in funcs
console.log("My value: " + i); // each should log its value.
};
Assigns a function to the array at whatever i is currently
}
End of loop
for (var j = 0; j < 3; j++) {
Sets j to 0, 1, 2, 3.
i is still 3.
funcs[j](); // and now let's run each one to see
Calls the first function. i is 3.
Calls the second function. i is 3.
Calls the third function. i is 3.
}
Fin.

IIFE and variable assignment in Javascript. Do we really need an IIFE? What is going on? [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
Say I have this function:
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
setTimeout( function() {
console.log( fruits[i]);
}, i * 1000);
}
}
printFruits(["Lemon", "Orange", "Mango"])
So this returns undefined 3 times.
I can see on a high level that since variables are stored not by value but by reference inside the closure... the loop is finishing first and by the time the functions are dequeued from maybe the Event Loop... the variable is already at undefined (fruits.length evaluates to 3 which is too high for this array size). But why does this perform strangely... it prints "apple" 3 times.
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
var someConstant = i;
setTimeout( function() {
console.log( fruits[someConstant]);
}, someConstant * 100);
}
}
printFruits(["mango", "banana", "apple"])
Shouldn't someConstant be changing as well with i? Why does it seem to be 2 always?
Also this works:
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
(function() {
var current = i;
setTimeout( function() {
console.log( fruits[current]);
}, current * 1000);
})();
}
}
Why is the IIFE necessary to fix this problem?
2nd Example
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
var someConstant = i;
setTimeout(function() {
console.log(fruits[someConstant]);
}, someConstant * 1000);
}
}
printFruits(["Lemon", "Orange", "Mango"])
This logs thrice Mango. Because everytime the someConstant variable is created and re-initialised to i. Recollect how for loop works. i-value is increasing here till 4, checks the condition 4<3, and terminates. So the matter inside the loop executes only thrice. So the last value of someConstant defined in the printFruits functional scope is 2. So when the inner function executes someConstant, its equal to 2. So we get each time Mango.
3rd example
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
(function() {
var current = i;
setTimeout(function() {
console.log(fruits[current]);
}, current * 1000);
})();
}
}
printFruits(["Lemon", "Orange", "Mango"])
Here the beauty of closures happening. Here its a self executing function being executed, immediately. So when i = 1, it invokes immediately. Every function has a different scope now. There is a seperate current value defined for each. So later when it executes, it recollects whats the value of 'current' when it was defined inside its scope.
The only difference between these samples is that the for loop increments i to 3 before stopping, while the last value which is assigned to someConstant is 2. Your "working" code is outputting Mango three times (index 2 of the array) instead of undefined (index 3 of the array). The general behaviour is the same.
Yes, you do need an IIFE, or ES6's let keyword instead of var.
The difference is that someConstant never gets incremented after the last iteration. The for() loop sets i = 3, the test i < fruits.length fails, so the loop stops. As a result, someConstant is still set to 2 from the last iteration of the loop. Then all the callbacks run, so they all log fruits[2], which is Mango.
You need the IIFE to get each iteration to save its value of i in the closure.

Categories