for循环与setTimeout结合面试问题巩固

for循环与setTimeout结合面试问题巩固

先来一个经典的面试题

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

最终的结果会是多少?

一秒后...
5
5
5
5
5
问题

1. 为什么输出的是5

2. 为什么输出的全部都是5

3. 为什么定时器是一秒后全部都输出,而不是每过一秒钟输出一个

解答

1. 为什么是5

因为使用的是var 全局变量,当for循环运行到最后一次的时候 4(i的值) += 1,只不过这个没有通过for循环的判定条件结束了,但是 4+=1却执行了 所以公共变量i的值是5

2. 为什么输出的全部都是5

因为javascript是单线程,所以有异步执行机制,先执行同步任务,后执行异步任务,for循环是同步任务,而setTimeout是异步任务,所以首先会执行for循环,当for循环执行完时i是5,这时候才开始执行异步任务,所以全部输出的都是5

3. 为什么定时器是一秒后全部输出,而不是每过一秒输出一个

当定时器回调时,是以执行的时间为起点经过设置的延迟时间后执行设置指令,for循环中执行的5次,但定时器的起点依然是第一次被回调的时间点,所以定时器是一秒后全部输出而不是没过一秒输出一次

这时候可能会问,有没有办法正确的输出i的值呢?

// 方法一
for(let i = 0; i < 5; i += 1)
{
    setTimeout(function() {
        console.log(i)
    },1000)
}
// 方法二
for (var i = 0; i < 5; i++) {
    setTimeout(
        (function (i) {
            return function () {
                console.log(i);
            };
        })(i),
        i * 1000
    );
}

结果

// 一秒后...
0
1
2
3
4
问题

1. 为什么使用var就不行,而let就行呢?

2. 在立即执行函数中return函数的作用是什么?

答案

1. 为什么使用var就不行,而let就行呢?

因为let是块级作用域,所以每一次的console.log(i)都是i当前的值,在定时器未执行前都不会被释放

2. 在立即执行函数中return函数的作用是什么?

我们需要立即执行函数只是为了获取到for循环作用域内的i值,而setTimeout的第一个参数必须是需要编译的代码或者一个函数方法,此时就需要return一个函数方法并接收立即执行函数传值完成以上效果

当我们需要隔一秒钟输入一次呢?

for(var i = 0; i < 5; i += 1)
{
    setTimeout(function() {
        console.log(i)
    }, i * 1000)
}
结果
5
// 一秒钟...
5
// 一秒钟...
5
// 一秒钟...
5
// 一秒钟...
5
问题解答

1. 为什么这样写会隔一秒输出一次?

在定时器第二个参数接收的i值为for循环作用域内的i值,当定时器开始执行时,是以执行时的时间为起点,根据第二参数设定的等待时间,进行执行, 所以随着i值变化也就是第二参数的变化进行定时器内函数的回调, 大致效果如下:

请1秒钟后console.log(i)
请2秒钟后console.log(i)
请3秒钟后console.log(i)
请4秒钟后console.log(i)
请5秒钟后console.log(i)

// 一秒钟后
5
// 两秒钟后
5
// 三秒钟后
5
// 四秒钟后
5
// 五秒钟后
5
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值