代码之家  ›  专栏  ›  技术社区  ›  temporary_user_name

为什么我使用“let”不能防止setTimeout和连续变量的经典闭包问题?

  •  0
  • temporary_user_name  · 技术社区  · 6 年前

    请参阅此代码:

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

    这是一个典型的错误,它会打印 i

    我知道它可以通过使用 let 而不是 var :

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

    让我困惑的是为什么会这样

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

    现在应该修复它,原因与前面的代码相同,但该错误仍然存在。为什么呢?

    2 回复  |  直到 6 年前
        1
  •  1
  •   Scott Marcus    6 年前

    您仍在引用 i setTimeout 回调函数,所以在它周围仍然有一个闭包。这和你第一个关于计时器的“经典”闭包问题的例子没有什么不同。

    原因是 let 这个例子避免了这个问题,即使

        2
  •  1
  •   Yehuda Makarov    6 年前

    有一种特殊的行为 let for循环头中的声明。对于每个迭代,该变量都是唯一声明的。这就是为什么示例2“有效”。

    var i 声明只发生一次,每次迭代都会更新该值。 允许 let n = i i 此时是单身 这是在for循环中声明的。

    https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch5.md#block-scoping-revisited

    console.log(a);
    var a = 10;
    

    将打印 undefined 因为在 console.log a 已声明但未分配。

    console.log(a);
    let (or const) a = 10;
    

    TypeError 因为在 console.log A. 还没有宣布。