【问题标题】:Arrow function closure within for loop [duplicate]for循环内的箭头函数闭包[重复]
【发布时间】:2017-11-16 22:55:24
【问题描述】:

鉴于此:

var m = 5;

for (i = 0; i < m; i++) { 
    add_row('row-'+(i+1), () => f(i))
}

如果我在f 中发出警报,它将始终输出值5。我相信这是由于这里提到的 python 存在同样的问题:

lambda function don't closure the parameter in Python?

这个问题在javascript中是如何解决的?

【问题讨论】:

  • python != javascript。我也没有看到你的f。您能否附上其内容的简短示例?
  • @Shadow 它的内容无关紧要。 i 的值是整个问题。

标签: javascript ecmascript-6


【解决方案1】:

这是因为add_row() 是异步的。当操作完成时,它会调用您稍后传递给它的回调。同时,for 循环已经完成。 ES6 中的一个简单解决方案是将letfor 循环一起使用。这将为循环的每次运行创建一个新的单独的 i 变量,因此当稍后调用回调时,用于该循环调用的变量 i 仍处于函数启动时的位置。

如果您要像这样在代码中插入一些 console.log() 语句:

var m = 3;

console.log("A");
for (i = 0; i < m; i++) { 
    console.log("B" + i);
    add_row('row-'+(i+1), () => {
        console.log("C" + i);
        f(i);
    })
}
console.log("D");

您将在控制台中看到的是:

 A
 B0
 B1
 B2
 D
 C0
 C1
 C2

注意“D”如何出现在任何“Cx”行之前。这向您展示了在您的 for 循环执行完成后如何调用异步回调。

请研究一下,当您完全理解该命令的原因时,您将最终理解异步回调。从技术上讲,C0、C1 和 C2 将位于末尾,但可以以任何相对于彼此的顺序排列。

以下是如何使用letfor 循环创建一个单独的变量i 为循环的每次迭代,这样当回调被调用一段时间时你仍然有i 的适当值稍后:

for (let i = 0; i < m; i++) { 
    add_row('row-'+(i+1), () => f(i))
}

在 ES6 之前,可以通过创建一个额外的闭包来解决这个问题,该闭包会创建一个新的函数作用域变量,以便为每次调用分别“记住”循环索引:

for (var i = 0; i < m; i++) { 
    (function(index) {
        add_row('row-'+(index+1), () => f(index))
    })(i);
}

【讨论】:

  • @Baz - 这回答了你的问题吗?如果是这样,您可以通过单击答案旁边的复选标记向社区表明这一点,并通过在 stackoverflow 上遵循正确的程序为自己赢得一些声誉积分。
猜你喜欢
  • 1970-01-01
  • 2019-05-28
  • 1970-01-01
  • 2018-12-26
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
  • 1970-01-01
  • 2022-08-20
相关资源
最近更新 更多