+ 11
JAVASCRIPT QUESTION... 🤔
What is the output of this code and why is it that way? https://www.sololearn.com/post/662769/?ref=app
21 Answers
+ 8
👑 Tchybooxuur! The output is 3 3 3 and not 0 1 2 as one would expect, due to scope and closure.
The variable i in addArr function has function scope due to it being declared using the keyword var.Thus effectively,addArr has only one declaration of i.An alternative representation of the code you've given above could look something like this
function addArr(){
var arr=[];
var i;
for(i=0;i<3;i++){
/*The rest of your code*/
}}
Now keep in mind that the functions stored in arr never hold a copy of i.This is not what closure is about
Whenever an inner function obtains closure over another function,the JS engine only prolongs the lifetime of those local variables.It never assigns a new copy to each new function.
Thus all the three functions,will access the same variable i when called,as they acquire closure of the inner scope of addArr function that has only one i.
I presume that I don't need to explain why i is 3 since I assume that you are already familiar with how loops work.
Hence the output is 3 3 3
+ 6
There are 2 ways of fixing this.
1.Using let as 🇮🇳Vivek🇮🇳 has just shown.Let introduces block scopes.Thus a new variable i is created at the start of each iteration and "destroyed" at that iteration's exit.Now all functions in arr will have closure over different i variables.(This might seem confusing at first but think about it deeply,you'll eventually see the logic)
2.If you insist on using var then you'll have to do what many JS programmers wrongly assume the engine does for them - create a copy of i yourself that is local to each new function!.I.e.
function addArr(){
/*part of your code*/
for(var i=0;i<3;i++){
arr.push(function (){
var j=i; //j is now a copy of i
console.log(j);
});
}
/*The rest of your code*/
+ 5
Anthony Maina
Thanks a lot for your explanations. They are very helpful. The second explanation is yet to totally sink though but I'll go through it a couple more times and hopefully it sinks for good.
+ 5
Anthony Maina I think your first answer and fix 1 of the second have successfully solved this question👍
However the second fix won't work because of the same reason you stated in your first answer.
If you want other alternatives you could:
1-) Use an IIFE to capture the value of "i" on each iteration and make our function enclose that value. Example:
arr.push(
(function(i){
return function(){
console.log(i);
})(i)
) // end push
2-) Add a parameter to the original function and bind "i" to it:
arr.push(
function(i){
console.log(i)
}.bind(null,i)
) // End push
+ 4
🇮🇳Vivek🇮🇳 The original code is using var instead let you which produces a different result. 3, 3, 3
+ 3
ODLNT oh. I didn't realise that. Question is in es5.
+ 3
🇮🇳Vivek🇮🇳
😅
Nice try. let was not used in the question.
+ 3
ODLNT
It would have been nicer if you tendered your own explanation.
+ 3
🇮🇳Vivek🇮🇳 I had the same urge to use let, but then from out of no where I heard the words "block scope"😉
+ 3
Théophile
I don't think you are right.
+ 3
Théophile
I'm not sure how to answer your question too... 😅😅😅
What is actually going on under the hood is a feature in Javascript and some other languages like python called closures.
The final value of i in the for loop is what's available in memory in the execution context of addArr which is 3. And it gets called 3 times.
+ 2
Théophile the main difference between var and let is var has weird part. But let doesn't have. So, people recommend to use let or const and not to use var.
variable declared with var is globally scoped. but variable declared with let and const is block scoped.
I don't know why it is giving 3, 3, 3 in console. Technical it should give 0, 1, 2.
+ 2
🇮🇳Vivek🇮🇳 I knew it is a better to use 'let' to declare variables, but the two different output here are quite surprising. 🤔
👑 Tchybooxuur! with 'var', it seems to work like in python, indeed.
In my first comment, I wrote 2 2 2 as the answer because I'm it would have been the result in Python 😅. I completely forgot the last 'i++' in the JS code.
+ 2
Anthony Maina Thanks. You really help me to understand this.
+ 2
Kevin ★ Yeah you're right
+ 1
I'm not sure at all, but since we capture the variable i, then the result would be 2 in each function call.
(it answer from my Python experience and I assume it behaves as lambda in Python).
+ 1
This because i is 0, 1, 2. And we are logging into console.
https://code.sololearn.com/cNoatM1oGofU/?ref=app
+ 1
👑 Tchybooxuur! Indeed... I tried to answer with my python knowledge. And I have to acknowledge that I don't understand the output here 😅.
I thought it was capturing the variable 'i', and not the value of 'i'. 🤔
+ 1
Oh! I realized that there is a difference between 'let' and 'var'.
With 'let', the output is 0 1 2 and with 'var', it is 3 3 3...
That's weird...
'var' declare 'i' for the whole function scope, while 'let' declares it for the loop scope only. Does that means that with 'var', the variable is captured, and with 'let', the value is copied?