【问题标题】:Why does variable declared within for loop is updated instead of being recreated on each iteration? [duplicate]为什么在 for 循环中声明的变量会更新而不是在每次迭代时重新创建? [复制]
【发布时间】:2016-03-15 10:45:27
【问题描述】:

这是一个代码:

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];

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

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

【问题讨论】:

    标签: javascript loops asynchronous closures


    【解决方案1】:

    使用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 声明变量,然后它们将具有您想要的块范围。因此,在最新的浏览器或 node.js 中,您可以使用let,它将具有所需的块范围:

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

    【讨论】:

    • 是的。但是变量 x 是在循环内创建的。它不是在外部范围内创建的,因此循环可以更改它。这是否意味着在循环内和循环外定义 x 变量没有区别?它无论如何都属于外部范围?
    • @RhinoLarva - 不,这不是 Javascript 的工作方式。无论您在何处找到 var 定义,都会在函数顶部创建变量。 Javascript 将所有 var 定义“提升”到函数顶部。该变量仅在for 循环中分配。它是在您的函数顶部创建的。请参阅我的第一个代码块,了解 Javascript 解释中真正发生的情况。如果您想了解更多关于“Javascript 变量提升”的信息,请在 Google 上搜索。
    • 是的,我知道什么是提升以及它是如何工作的。问题在于我认为在循环中声明的变量仅在循环内可用,并且在每次迭代时重新创建。感谢您的回答,尤其是对于“等效”代码 sn-p。现在说得通了。
    猜你喜欢
    • 2014-12-01
    • 1970-01-01
    • 2018-04-07
    • 2012-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-13
    • 1970-01-01
    相关资源
    最近更新 更多