面试中在谈论闭包的时候有让实现一个倒计时功能,当时满脑子都是那个setTimeout压入栈不断输出循环尾数的例子,最后也是没有用闭包实现倒计时
首先来看看那个在循环中不断重复输出的setTimeout代码片:
var countDown = function(){
for(var i=10;i>0;i--)
{
setTimeout(function(){console.log(i);},1000);
}
}
输出效果:
当然这个是没有实现倒计时功能的,原因呢:
首先,和setTimeout设置的时间是没有关系的,很多人怀疑是时间设置的问题,不信可以将时间设置为0,结果是一样的,这里就不演示了
当然,得分析分析setTimeout的循环机制:setTimeout是从队列结束的时候开始计时的,如果前面有进程没有结束,那么它就等到它结束再开始计时,在这里呢,任务队列就是它自己所在的循环。循环结束setTimeout才开始计时,所以无论如何,setTimeout里面的i都是最后一次循环的
解决方法呢如下:
var countDown = function(){
for(var i=10;i>0;i--)
{
var a =function(v){
return function(){
console.log(v);
}
}
setTimeout(a(i),1000);
}
}
因为setTimeout的第一个参数需要一个函数,所以返回一个函数给他,返回的同时把i作为参数传进去,通过形参v缓存了i,并带进返回的函数里面
当然了,这样写也是可以的:
var countDown = function(){
for(var i=10;i>0;i--)
{
var a =function(v){
console.log(v);
}
setTimeout(a(i),1000);
}
}
总之呢:例子中遇到setTimeout的问题,原因就是回调等待循环队列结束造成的,解决的办法就是给回调函数传一个实参缓存循环的数据