闭包在循环中的应用
延迟函数的回调会在循环结束时才执行;
事实上,当定时器运行时即使没给迭代中执行的是 setTime(..., 0)
,多有的回调函数依然是在循环结束后才会被执行,因此会每次输出一个6出来。
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循环结束----"+now.toLocaleTimeString() + "." + now.getMilliseconds());
}
}
// for循环结束----下午7:51:29.885
// 6----下午7:51:30.885
// 6----下午7:51:31.885
// 6----下午7:51:32.885
// 6----下午7:51:33.885
// 6----下午7:51:34.885
利用立即执行函数创建作用域,但作用域为空(没有传参),并未奏效;
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循环结束----"+now.toLocaleTimeString() + "." + now.getMilliseconds());
}
}
在立即执行函数中捕获一个变量
for (var i = 0; i <= 5; i++){
(function(){
var j = i; // IIFE有了自己的变量
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循环结束----"+now.toLocaleTimeString() + "." + now.getMilliseconds());
}
}
// for循环结束----下午8:14:28.915
// 0----下午8:14:28.916
// 1----下午8:14:29.916
// 2----下午8:14:30.916
// 3----下午8:14:31.916
// 4----下午8:14:32.916
// 5----下午8:14:33.916
改进
1. 利用立即执行函数(IIFE)传参
利用立即执行函数为每个迭代都生成一个新的作用域,使得延迟函数的回调可以将新的作用域封闭在每个迭代内部;
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);
}
2. 利用setTimeout
给回调函数(callback
)中传参,产生timer
对for
循环作用域的闭包
利用延迟函数向其回调函数中传参,为每个迭代中callback
中生成新的作用域,使得延迟函数的回调可以将新的作用域封闭在每个迭代内部;
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);
}
3. 利用let
声明劫持块作用域
本质:将一个块转换成了一个可以被关闭的作用域。
for(var i=0; i<5; i++){
let j = i;// 闭包的块作用域
setTimeout(function timer(){
console.log(j);
}, j*1000);
}
4. 利用for
循环头部的let
声明
for
循环头部的let
声明的特殊行为:使得变量i
在循环过程中不止被声明一次,每次迭代都会声明。
随后的每个迭代都会使用上一个迭代结束时的值来初始化这个变量。
for(let i=0; i<5; i++){
setTimeout(function timer(){
console.log(i);
}, i*1000);
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。