📅  最后修改于: 2023-12-03 14:57:02.459000             🧑  作者: Mango
在编写 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 代码时,由于作用域和闭包的特性,我们需要特别小心变量的引用关系。在使用异步函数时,尤其需要注意变量的值是否已经被修改,以免出现类似问题。使用立即执行函数可以解决很多这样的问题。