📌  相关文章
📜  网络技术问题 | JavaScript 课程测验 1 |问题 36(1)

📅  最后修改于: 2023-12-03 14:57:02.459000             🧑  作者: Mango

JavaScript 课程测验 1 | 问题 36

问题描述

在编写 JavaScript 代码的过程中,你遇到了以下问题:

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

代码运行后,控制台输出了一连串的数字 6。请解释问题出在哪里,以及如何修改代码。

问题分析

这段代码的目的是输出数字 1 至 5,每个数字间隔 1 秒。但是实际上,代码输出了一连串的数字 6。这是因为 setTimeout 是异步函数,for 循环会在 5 次迭代之后才结束,此时 i 的值已经变为 6。由于闭包的特性,在 setTimeout 中访问的变量 i 是对同一个变量的引用,因此最后输出的是 6。

修改方案

要解决这个问题,可以使用立即执行函数来创建一个新的作用域,并将 i 传递给 setTimeout 函数。这样,setTimeout 中访问的变量 i 就是传递进去的值,而不是外层作用域中的变量 i。

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

在上述代码中,通过创建立即执行函数并将 i 传递给它,我们得到了一个新的变量 j,它与外层的 i 没有任何关系。在 setTimeout 的回调函数中,访问的是新的变量 j,因此输出的结果就是预期的 1 至 5。

总结

在编写 JavaScript 代码时,由于作用域和闭包的特性,我们需要特别小心变量的引用关系。在使用异步函数时,尤其需要注意变量的值是否已经被修改,以免出现类似问题。使用立即执行函数可以解决很多这样的问题。