Tricky little Javascript Questions

Claudia
4 min readOct 12, 2021

We always see those tricky little Javascript questions and I have just stumbled onto one that had me stumped for a little while. I decided to do a quick write-up about this. Hopefully, it will help someone understand it a bit better.

The question — Part 1.

Given this JS snippet, what would print to the console?

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

Having a quick look at this, you might answer that it would just log out 0–4 to the console after 1 second.

That would be incorrect. It will log the number 4to the console 5 times. What? I’ll explain this soon, but first, let’s go to the next part of the question.

The question — Part 2

The code will change slightly to look like so. Notice that we have removed the number variable from the question and we are now logging i.

Given this change, what will this log to the console?

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

0–4 after 1 second? Nope! This will log 5 to the console 5 times.

Brain explodes! Why? I will get to that soon. Let’s now change the code one more time. Let’s change to use let instead of var in the for-loop.

The question — part 3

Given this final change,what do you think will log to the console?

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

That’s right! In this scenario, we will get 0–4 printed to the console.

The explanation.

To better explain what is happening, I will rewrite this using a while loop.

Explanation — part 1

Let’s analyse the first question. We had a declaration at play called number and we assigned the variablei to it. Rewriting it as a while loop, it will look like so. The number declaration is set outside the loop and so the scope sits where it is originally declared. Read more about let

var i=0;
let number;
while(i<5){
number=i;
setTimeout(function(){
console.log(number);
},1000);
i++;
}

If you look above, we are saying that while i is less than 5, which means i needs to equal a maximum of 4, we will set number to whatever i is at that point in time, we will then move the console.log to the browser’s queue and bring it back after a second, we can then increment i by 1.

If we were logging i, the answer would be 5 as in the final step of the loop, we still increment i by 1 . In this condition, however, we only allow number to equal i if i is less than 5. The maximum number that it could be is 4.This means we will print 4 to the console 5 times.

Explanation — part 2

So what is happening here? Let’s look at the second example written out as a while loop.

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

Looking at the above function, we are seeing that initially our variable i equals 0. Cool beans. While i is less than 5 we want to increment i to be its value + 1;

So, while i=4,which is less than 5, our setTimeout is added to the browser’s queue to be run in one second.

We then have to run the next statement which is i++ so i is now equal to 5.

Finally, a second later, we bring the console.log(i) back into play and at this point the answer is 5 and of course, it runs 5 times.

Explanation — part 3

In the last example, we are using let within the loop instead of var. This means that it is scoped to the block, which happens to be within the loop. The let declaration will cause there to be a distinct i for each iteration of the loop.

let i=0;
while(i<5){
let scopedCopy = i; // creating a copy of i to mimic the loop
setTimeout(function(){
console.log(scopedCopy);
},1000);
i++;
}

Every time this loops, the value ofscopedCopy will be specific for that loop itself. Think of it as unique copies of i.

Therefore, every time the loop runs, the version of i is different. It will log 0–4 to the console after a second

How did they use to do it before let and const?

If this is the case? How did they use to get around this before let and const were in the picture? The way around this would be to create a function that takes in i as an argument like so;

function logUtil(i) {
setTimeout(function() {
console.log(i);
}, 1000);
}

for (var i=1; i<5; ++i){
logUtil(i);
}

Hope this makes sense! If you have any feedback or think there is an amendment to be made, please reach out.

--

--