Closures:
1. First Loop (with differentScope function):
for(var i=1;i<=5;i++){
const differentScope = (i)=>{
setTimeout(()=>{
console.log(i)
},i*1000);
}
differentScope(i);
}
Output: 1 2 3 4 5 (each number printed at 1-second intervals)
Explanation:
We're using
varfor the loop variableiInside each iteration, we create a function
differentScopethat takesias a parameterWe immediately call
differentScope(i)with the current value ofiBecause
iis passed as a parameter to the function, it creates a new scope for each iterationEach setTimeout gets its own copy of
ifrom its scopeThis works correctly, printing 1 through 5 at 1-second intervals
2. Second Loop (plain varwith setTimeout):
for(var i=1;i<=5;i++){
setTimeout(()=>{
console.log(i)
},i*1000);
}
Output: 6 6 6 6 6 (each 6 printed at 1-second intervals)
Explanation:
We're using
varwhich is function-scoped, not block-scopedThe loop completes before any setTimeout callback runs
By the time the callbacks execute,
ihas already reached 6 (the loop stops whenibecomes 6)All callbacks share the same
ivariable, which is now 6The delays are still 1s, 2s, etc. because
i*1000is evaluated during the loop iteration
3. Third Loop (using let):
for(let i=1;i<=5;i++){
setTimeout(()=>{
console.log(i)
},i*1000);
}
Output: 1 2 3 4 5 (each number printed at 1-second intervals)
Explanation:
We're using
letwhich is block-scopedIn a
forloop withlet, a new binding is created for each iterationEach setTimeout callback gets its own
ifrom its respective iterationThis works correctly, printing 1 through 5 at 1-second intervals
Key Differences:
The first loop works because we're passing
ito a function, creating a new scope for each iteration.The second loop fails because
vardoesn't create a new binding for each iteration, and all callbacks share the samei.The third loop works because
letcreates a new binding for each iteration in aforloop.
This demonstrates why let is generally preferred in modern JavaScript for loop variables, especially when dealing with asynchronous operations inside loops.