interview1 : for循环+setTimeout

今天听同学说了个很好玩的面试题,个人觉得很有意思,故在此写点自己的看法。

问题是这样的:当setTimeout在for循环中出现时,在定时器中打印控制for循环的变量,但后来打印的时候,会发现,打印出来的结果是重复了变量满足最后一个条件的值。

话可能说的不是很清楚,我们通过代码来看看到底是怎么回事。在此之前,需要注意的一点是,setTimeout是异步执行的。

for (var i = 0; i < 5; i++) {
    setTimeout(function () {
        console.log(new Date, i);
    }, 1000)
}
console.log("for循环外:", new Date, i)

然后打印的结果是这样的,
在这里插入图片描述
很明显,这不符合我们的需求,我们想要实现的应该是每间隔1秒打印从0递增到4的i值。

那么,有什么解决办法吗?还真有,而且,据我查的资料来看,目前有3种方法。

不过,虽然方法不同,但基本上原理差不多,都是改变作用域,把变量私有化

方法1: 使用闭包

逻辑:如果每次for循环时将 i 的值保存起来,等到定时器里执行console.log(i)的时候再去调用保存好的 i 的值,是不是就可以输出i的不同取值了呢?

基于这种思想,可以使用闭包,形成私有作用域。这时每次for循环传入的 i 的值都将作为私有变量被保存在内存中,等待for循环执行完毕后,跟随任务队列输出。

for (var i = 0; i < 5; i++) {
    (function (j) {
        setTimeout(function () {
            console.log(new Date, j);
        }, 1000)
    })(i)
}
console.log("for循环外:", new Date, i)

在这里插入图片描述

方法2: 封装函数

逻辑:对settimeout进行封装,改变作用域,使得每次调用定时函数都有自己的私有变量值。

for (var i = 0; i < 5; i++) {
    fun(i)
}
console.log("for循环外:", new Date, i);

function fun(i) {
    setTimeout(function () {
        console.log(new Date, i);
    }, 1000);
}

在这里插入图片描述

方法3: setTimeout() 自身第三个参数的巧妙使用

setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式,第三个参数是传给执行函数的其他参数。

for (var i = 0; i < 5; i++) {
    setTimeout(function (k) {
        console.log(new Date, k);
    },1000,i)
}
console.log("参数for循环外:", new Date, i)

在这里插入图片描述

不成方法的方法: 将 var 换成 let

还可以用let,let是ES6新增用来声明变量的,一般用在声明局部变量中。let声明的变量的范围会生成一个私有作用域,也叫作块级作用域,该变量只会在当前作用域中生效,以 { } 为标识。

所以,如果用let的话,外层的打印的i是未被定义的。

for (let i = 0; i < 5; i++) {
    setTimeout(function () {
        console.log(new Date, i);
    }, 1000)
}
console.log("for循环外:", new Date, i)

在这里插入图片描述

以上就是我总结的4种方法,不过let最好不能算作一种方法。

然后,这边还有一些原理性的问题我没有提到,提供两篇大神的博客,仅以参考。

参考1:js经典面试题:setTimeout+for循环组合,使用闭包循环输出1,2,3,4,5(CSDN)

参考2:JS 异步编程六种方案(简书)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值