一道经典题目的分析和解法方法详解编程语言

1 for(var i = 0; i < 5; i++) { 
2     setTimeout(function() { 
3         console.log(i); 
4     }, 2000) 
5 }

这段代码大家都不陌生吧,相信很多久经面试的小伙伴一定不陌生。可是是不是还有很多人不理解其中的原因,现在我就带大家一起详细的分析一下。

先让我们看一下最基本写法:

1 for(var i = 0; i < 5; i++) { 
2     console.log(i); 
3 }

这个毫无疑问应该是0,1,2,3,4。可以为啥加一个函数就不行了呢?当初我也迷糊了好久。好了,不买关子了,让我们来看一下最开始的那个函数,一步一步来分析。首先当i = 0 时,执行了一个setTimeout这样一个异步函数,里面输出一个i,应该是0没错吧,可是别忘了函数不是立即执行的,而是要等一秒之后才进行的。然而这时循环并不会停止,继续循环。i = 1;又调用了一个异步函数,里面输出一个i,此时应该是1。可是i对于函数是共享的,所以之前那个本应该输出0的异步函数中i在这时被替换成了1。现在是不是就有两个输出1的异步函数了。2,3,4类似,因为每一步前面的i值都会被替换,最后都换成了最后一个值。应该是5个4。可是当循环i=4时还要+1,i成了5虽然循环没有进行了,但是i最后被赋值成了5,所以所有的i就成了5了。输出了5个5,呼,终于真相大白了。

现在让我们研究一下,如何才能按照正常的值输出1,2,3,4呢。解决方法就是让每一步的i对于函数都是单独的不会因为共享而被替换。

方案1:添加一个立即执行函数将i立刻传到函数中成为函数的参数,因为后面的i值得变化并不会改变之前函数的参数值

1 for(var i = 0; i < 5; i++) { 
2     (function(j) { 
3         setTimeout(function() { 
4             console.log(j); 
5         }, 1000) 
6     })(i) 
7 }

方案2:利用ES6特性let,因为let时块级作用域,所以并不会影响之前复制的i的值

1 for(let i = 0; i < 5; i++) { 
2     setTimeout(function() { 
3         console.log(i); 
4     }, 1000) 
5 }

方案3:其实setTimeout这个函数还有第三个参数甚至更多,从第三个参数起,后面的参数为传入函数中的参数,因为原理与第一种方法类似

1 for(var i = 0; i < 5; i++) { 
2     setTimeout(function(j){ 
3         console.log(j); 
4     }, 1000, i) 
5 }

其实解决方案应该远不止这么多,但是原理都是一样的,所以就不一一列举了,喜欢研究的小伙伴可以分享一下其它方法……

 

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/16606.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论