【发布时间】:2017-12-31 06:45:11
【问题描述】:
让我澄清一下我的问题。我不是在问如何使以下代码工作。我知道您可以使用 let 关键字或 iffe 来捕获它自己的 i 值。我只需要说明如何在以下代码中访问值i。我阅读了以下博客文章,了解以下代码如何不起作用。 Blog post
for (var i = 1; i <= 5; i++) {
setTimeout(function() { console.log(i); }, 1000*i); // 6 6 6 6 6
}
作者声称代码将不起作用,因为我们将变量 i 作为引用而不是值传递。也就是说,我们不是在每次迭代中提供i 的值,而是将变量提供给setTimeout 中的回调作为参考。实际上,当循环终止并触发回调时,我们将引用变量i,即 6。这是它的工作原理吗?
这是我的理解。我的理解是,当循环被执行时,我们没有向setTimeout 函数的回调“传递”任何东西。我们只是设置异步调用。当闭包回调函数执行时,它们会根据词法范围规则查找变量i。也就是说,闭包在作用域中看起来是回调已经结束了,在这种情况下,这也是 6,因为它是在 for 循环完成之后完成的。
它是哪一个,该函数是根据在每次迭代中作为引用传递的变量还是因为词法作用域而将 i 的值解析为 6?
【问题讨论】:
-
有趣的是,如果你设置超时时间为 0 毫秒,你仍然会得到 66666!
-
@JonMarkPerry 那是因为 JS 是单线程的。当计时器触发时,超时被添加到消息队列中(即暂停只是最小延迟)。 MDN 在the Event Loop 上有一篇很棒的文章,您可以在其中阅读它
-
@Kiren; vg,所以我们在执行 sT 之前等待 for...loop 队列清空,此时
i为 6,除非我们使用闭包。 -
你可以使用
setTimeout(console.log(eval(i))); -
"然后他们根据词法范围规则查找变量 i。" - 如果没有对所述词法范围的引用,这怎么可能? (当然,无论是对整个作用域的引用还是对单个变量的引用,以及“按规则查找”何时完成,都是实现细节,需要优化)。
标签: javascript settimeout