欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaScript经典面试题 —— 解决循环打印问题

程序员文章站 2022-06-09 19:13:21
...

循环打印问题是面试中经典的题目,一般会给出代码,让我们解释原因,并给出若干解决方案。

1. 题目分析

以下代码运行后会打印什么?

答案:6 6 6 6 6

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

虽然每个for循环中定时器设置的时间都是0,但由于JavaScript是单线程 eventLoop机制,setTimeout是异步任务,遇到setTimeout函数时,JavaScript会将其放入任务队列中,待同步任务执行完毕后,才执行任务队列中的异步任务

又因为setTimeout函数也是一种闭包,往上找它的父级作用域链window,而变量i是用var声明的,是window上的全局变量,所以此时变量i的值已经变成i = 6了,最后执行setTimeout时,当然会输出5个6了!

2. 解决办法

如果就是要输入1 2 3 4 5,该怎么办呢?

1. 立即执行函数

立即执行函数可以锁定参数值,传入每次循环的当前索引,从而锁定索引值。

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

2. 使用let声明(块级作用域)

利用JavaScript的块级作用域,就不用这么麻烦了。如果for循环使用块级作用域变量关键字,循环就会为每个循环创建独立的变量,从而每次打印都会有正确的索引值。

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

3. 定时器传入第三个参数

一般我们使用setTimeout都会使用2个参数,回调函数延迟时间,但setTimeout使用第三个参数的。

一旦定时器到期,会将第三个参数作为参数传递给回调函数。这样打印时,也能得到正确的索引值。

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

????????欢迎在我的博客*问:
https://lzxjack.top/