循环中IIFE函数与setTimeout()的运行逻辑解析请求
Let's walk through exactly what's happening with both code snippets when you run them in Node.js—this all boils down to how JavaScript handles variable scope and closures with asynchronous functions like setTimeout.
1. 标准写法的运行逻辑
First, here's the code again for reference:
for (var i = 0; i < 10; i++) { // Standard setTimeout(function() { console.log("Standard" + i); }, 1000 * i); }
What's actually going on:
- The
forloop runs synchronously first. Sincevaris function-scoped (not block-scoped), there’s only one singleivariable shared across the entire loop. By the time the loop finishes,ihas incremented to10(the loop stops wheni < 10evaluates to false). - Each
setTimeoutschedules a callback function to run after1000 * imilliseconds. But callbacks don’t execute immediately—they get queued in Node.js’s event loop. When each callback finally runs, it looks up the value ofi... which is already10by then. - So your output will look like this:
- After 0ms:
Standard10 - After 1000ms:
Standard10 - ... up to 9000ms:
Standard10
- After 0ms:
- Even though the callbacks fire at 1-second intervals (thanks to the
1000 * idelay), every log uses the final value ofi.
2. IIFE写法的运行逻辑
Now let's break down the IIFE (Immediately Invoked Function Expression) version:
for (var j = 0; j < 10; j++) { // IIFE (function(j) { setTimeout(function() { console.log("IIFE " + j); }, 1000 * j); })(j); }
What's different here?
- The IIFE
(function(j) { ... })(j)creates a new function scope for each loop iteration. When we passjas an argument to the IIFE, we’re making a local copy ofjthat’s unique to that specific iteration. - Now, when
setTimeout's callback runs, it "closes over" this localjvariable from the IIFE’s scope—not the sharedjfrom the loop. Since each IIFE has its ownj(with the value from that loop iteration), the callback logs the correct number every time. - Your output will match what you’d expect:
- After 0ms:
IIFE 0 - After 1000ms:
IIFE 1 - ... up to 9000ms:
IIFE 9
- After 0ms:
- Just like the standard loop, callbacks fire at 1-second intervals, but now each one uses the value of
jfrom when it was scheduled.
Why does the IIFE fix the problem?
The core issue with the standard loop is that var doesn’t create block-scoped variables—so all callbacks reference the same single i. The IIFE fixes this by:
- Spinning up a new function scope for every loop iteration.
- Capturing the current value of
jas a parameter in that scope, giving eachsetTimeoutcallback its own "private" variable to reference later.
As a quick side note: In modern ES6+ JavaScript, you could also fix this by swapping var for let in the loop. let is block-scoped and automatically creates a new variable for each iteration, making it a cleaner alternative to IIFEs these days!
内容的提问来源于stack exchange,提问作者Alberto Favaro

