循环中解决var定义函数的问题

9ccad8ada0cb44a7b67f7e2254ae3058.png

  在上述代码中,setTimeout 是个异步函数,所以会先把循环全部执行完毕,这时候 i 就是 6 了,所以会输出一堆 6。

解决办法有三种:

1、使用闭包的方式+立即执行函数

68678f3f550944f79b8ce50834c7be3e.png

 首先使用立即执行函数将 i 传入函数内部,这个时候值就被固定在了参数 j 上面不会改变,当下次执行 timer 这个闭包的时候,就可以使用外部函数的变量 j,从而达到目的。

2、使用 setTimeout 的第三个参数

f6c0f38c7b644e5aa661e69689469827.png

这个参数会被当成 timer 函数的参数传入,先行执行。

3、使用 let 定义 i

74ba47c00cc844949830937b0f034b54.png

其原理是:

在var里面,setTimeout是异步执⾏,i * 1000ms 后往任务队列⾥⾯添加⼀个任务,只有主线线上的全部执⾏完,才会执⾏任务队列⾥的任务,当主线执⾏完成后,i 是 6,所以此时再去执⾏任务队列⾥的任务时,i 全部是6了。

 每⼀次for循环的时候,settimeout都执⾏⼀次,但是⾥⾯的函数没有被执⾏,⽽是被放到了任务队列⾥⾯,等待执⾏,for循环了6次,就放了6次,当主线程执行完成后,才进入任务队列里面执行。

而在let里面,因为for循环头部的 let 不仅将 i 绑定到 for 循环中,事实上它将其重新绑定到循环体的每一次迭代中,确保上一次迭代结束的值重新被赋值。setTimeout里面的function()属于一个新的域,通过var定义的变量是无法传入到这个函数执行域中的,通过使用let来声明块变量能作用于这个块,所以function就能使用 i 这个变量了。

注意:

  由于 var 命令的变量提升机制,var 命令实际只会执行一次,而 let 命令不存在变量提升,所以每次循环都会执行一次,声明一个新变量(但初始化的值不同),for 的每次循环都是不同的块级作用域,let 声明的变量也是块级作用域,所以也不存在重复声明的问题,let 声明变量的 for 循环里,每个匿名函数实际上引用的都是一个新的变量。

猜你喜欢

转载自blog.csdn.net/m0_65835778/article/details/125676595
今日推荐