javascript - 为什么在 for 循环中声明的变量会更新而不是在每次迭代时重新创建?

标签 javascript loops asynchronous closures

这是一个代码:

var data = [ 'data1', 'data2', 'data3' ];

for (var i = 0; i < data.length; i++) {
    var x = data[i];
    setTimeout(function() {
        console.log(x);
    }, i * 100);
}

输出是“data3”的 3 倍。我的问题是为什么?

我知道所有 3 个日志方法将在循环完成后调用,并且变量 i 将等于 3,但是!

我在循环内定义 x 变量。我期望在每次循环迭代时在本地重新创建该变量,以便在调用每个 console.log(x) 方法时它们引用存储在内存中的 3 个不同变量。

但它看起来像代码:

var x = data[i];

更新相同的变量而不是重新创建它。

有人可以解释一下这种行为吗?

最佳答案

使用var声明的变量具有函数作用域。这意味着整个函数中只有一个具有该名称的变量。 var 声明在哪里并不重要。函数声明隐式“提升”到函数顶部,并且是整个函数可用的单个变量。

您的代码与此等效,这说明了为什么只有一个 x 实例被所有 setTimeout() 调用共享:

var data = [ 'data1', 'data2', 'data3' ];
var x;

for (var i = 0; i < data.length; i++) {
    x = data[i];
    setTimeout(function() {
        console.log(x);
    }, i * 100);
}

您可以通过在适当的位置引入一个函数来解决您的问题,以便在其自己的函数范围内唯一捕获 x 的每个值:

var data = [ 'data1', 'data2', 'data3' ];

for (var i = 0; i < data.length; i++) {
    (function(x) {
        setTimeout(function() {
            console.log(x);
        }, i * 100);
     )}(data[i]);
}

在最新的 ES6 中,可以使用 let 声明变量,然后它们将具有您想要的 block 作用域。因此,在最新的浏览器或 Node.js 中,您可以使用 let ,它将具有所需的 block 范围:

var data = [ 'data1', 'data2', 'data3' ];

for (var i = 0; i < data.length; i++) {
    let x = data[i];
    setTimeout(function() {
        console.log(x);
    }, i * 100);
}

关于javascript - 为什么在 for 循环中声明的变量会更新而不是在每次迭代时重新创建?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34191043/

相关文章:

c# - C# 编译器能否区分 I/O 绑定(bind)任务和计算任务?

javascript - Try/catch block 和未处理的 promise 异常

javascript - 显示带有拟合链接的随机图像

javascript - Javascript-在错误处理情况下抛出异常

javascript - 为多个 for 循环重新定义变量,好的还是坏的做法?

Javascript 异步请求不起作用

python - 如何在 python 中设计异步管道模式

javascript - SEO ajax 和链接

python - 非常奇妙的循环行为 : lists changes identity. 发生了什么?

python - 以有效的方式从列表中消除特定元素的函数