The application of closure in loop
for(var i=1; i<=5; i++){ setTimeout( function timer(){ let temp = new Date(); console.log(i + "----" + temp.toLocaleTimeString() + "." + temp.getMilliseconds()); }, i*1000); if(i == 5){ var now = new Date(); console.log("for Loop end----"+now.toLocaleTimeString() + "." + now.getMilliseconds()); } } // End of for cycle - 7:51:29.885 PM // 6 ---- 7:51:30.885 PM // 6 ---- 7:51:31.885 PM // 6 ---- 7:51:32.885 PM // 6 ---- 7:51:33.885 PM // 6 ---- 7:51:34.885 PM
The callback of the delay function will be executed at the end of the loop;
In fact, when the timer is running, even if setTime(..., 0) is not executed in the iteration, many callback functions will still be executed after the end of the loop, so 6 will be output each time
for (var i = 0; i <= 5; i++){ (function(){ setTimeout(function timer(){ let temp = new Date(); console.log(i + "----" + temp.toLocaleTimeString() + "." + temp.getMilliseconds()); }, i*1000) })(); if(i == 5){ var now = new Date(); console.log("for Loop end----"+now.toLocaleTimeString() + "." + now.getMilliseconds()); } }
for (var i = 0; i <= 5; i++){ (function(){ var j = i; // IIFE has its own variables setTimeout(function timer(){ let temp = new Date(); console.log(j + "----" + temp.toLocaleTimeString() + "." + temp.getMilliseconds()); }, j*1000) })(); if(i == 5){ var now = new Date(); console.log("for Loop end----"+now.toLocaleTimeString() + "." + now.getMilliseconds()); } } // End of for cycle - 8:14:28.915 PM // 0 ---- 8:14:28.916 PM // 1 ---- 8:14:29.916 PM // 2 ---- 8:14:30.916 PM // 3 ---- 8:14:31.916 PM // 4 ---- 8:14:32.916 PM // 5 ---- 8:14:33.916 PM
Improvement 1: using immediate execution function (IIFE)
The immediate execution function is used to generate a new scope for each iteration, so that the callback of delay function can close the new scope in each iteration;
for (var i = 0; i <= 5; i++){ (function(j){ setTimeout(function timer(){ let temp = new Date(); console.log(j + "----" + temp.toLocaleTimeString() + "." + temp.getMilliseconds()); }, j*1000) })(i); }
Improvement 2: use setTimeout to pass parameters to callback function to generate timer's closure to for loop scope
Using the delay function to pass parameters to its callback function, a new scope is generated for the callback in each iteration, so that the callback of the delay function can close the new scope in each iteration;
for (var i = 0; i <= 5; i++){ setTimeout(function timer(j){ let temp = new Date(); console.log(j + "----" + temp.toLocaleTimeString() + "." + temp.getMilliseconds()); }, i*1000, i); }