The variable x refers to different things in both examples when performing div.textContent =x;. Starting with your second example first, the value of x when performing div.textContent =x; is obtained from the outer scope of your setTimeout callback function, ie, your global let x = 0; declaration:
let div = document.querySelector('div')
let x = 0; <-----------------+
while (x < 10) { |
(function() { |
setTimeout(function() { |
div.textContent = x; --+
}, 1000 * x)
x++;
})()
}
The above loop iterates 10 times, each iteration it:
Invokes the IIFE
When the IIFE runs, it queues a callback using setTimeout(). This callback is only run after your synchronous while() loop has completed all of its iterations
Increments x after queuing your setTimeout calls.
Point is 2 is the main point here. Because all of your callback functions queued by each setTimeout() call are only invoked after your while loop has completed, x at the time that your callback executes will be set to 10. As outlined above, your callback functions all refer to the x declared in the global scope (which is now 10), and so your HTML content will only update with the value of 10.
For your second example, your x refers to the argument of the IIFE, and not the globally declared variable. When you invoke your IIFE, you're passing in the current value of x that you're iterated on and then incrementing it (with x++). This allows the body of the IIFE to have its own independent "copy" of x that is scoped locally to the IIFE body, and can't be accessed from outside the IIFE. The callback in the setTimeout() references this local version of the x and not the global one. It might be clearer if you call the formal parameter of your IIFE something other than x (such as y) to highlight that incrementing x from the outer scope doesn't influence the x from within the inner scope of IIFE:
while(x<10){
(function(y){ <------------+
setTimeout(function(){ |
div.textContent =y; ---+
},1000*x)
})(x++)
}
For each iteration of the while loop:
You invoke your IIFE, passing in the value of x as an argument, and then incrementing it using x++
The IIFE runs, creating a new scope with local variables of its own. In this case y (in your example x), is local to the IIFE and takes the value of the x value that was passed into the function when it was called.
A call to setTimeout() queues a callback. The queued callback is only after your loop has completed.
The main difference in this example as opposed to the first is that the callback here references the local y variable for each function IIFE created. So even though the callbacks are called after your while loop has finished and the global value for x is now 10, each setTimeout() callback will refer to the local y variable created when the IIFE was invoked, where y refers to the value of x for that particular iteration.