实现异步循环--闭包
让我们试着写一个异步方法,每秒打印一次循环的索引值。
for (var i=0; i<5; i++) {
setTimeout(function(){
console.log(i);
}, 1000 * (i+1));
}
如上程序的输出为:
> 5
> 5
> 5
> 5
> 5
这明显是有问题的。
原因
每次时间结束(timeout)都指向原始的i
,而并非它的拷贝。所以,for循环使i
增长到5,之后timeout
运行并调用了当前i
的值(也就是5)。
好吧,这个问题看起来很简单。最直接的解决方法是将循环的索引缓存在一个临时变量里。
for (var i=0; i<5; i++) {
var temp = i;
setTimeout(function(){
console.log(temp);
}, 1000 * (i+1));
}
但是再次运行,如上的程序输出为:
> 4
> 4
> 4
> 4
> 4
这仍然有问题,这是因为并不存在块作用域,而且变量的声明被提升到了作用域顶端。实际上,如上代码和下面是一样的:
var temp;
for (var i=0; i<5; i++) {
temp = i;
setTimeout(function(){
console.log(temp);
}, 1000 * (i+1));
}
解决方法
有几个不同的方式可以拷贝i
。最普通且常用方法是通过声明函数来建立一个闭包,并将i
传给此函数。我们这里使用了自调用函数。
for (var i=0; i<5; i++) {
(function(num){
setTimeout(function(){
console.log(num);
}, 1000 * (i+1));
})(i);
}
在JavaScript里,参数是按值传递给函数的。像Number
、Date
和String
这些原始类型为基本复制。当你们在一个函数内改变它的值,并不影响外面的作用域。但Object
类型不一样:如果你在函数内部修改了它的参数,将会影响到所有包含该Object
的作用域内它的参数。
另一种方法是使用let
。在ES6中的let
关键字是可以实现的,它和var
不一样,因为它支持块作用域的。
for (let i=0; i<5; i++) {
var temp = i;
setTimeout(function(){
console.log(i);
}, 1000 * (i+1));
}
分类:
javascript
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 我与微信审核的“相爱相杀”看个人小程序副业
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求