我需要一些解释才能清楚地了解这里发生的事情;
我们有这两个代码示例,第一个记录到控制台 -1五次,这是因为for循环执行完全离开i的值为-1,然后才执行回调开始执行。问题 是,当它们执行时,我已经具有值-1。
第二个样本记录了5到1倒计时的预期结果。两个样本之间的唯一区别是i不再在countdown()
函数的范围内声明,但为什么更改执行以及第二个样本中i的值是如何处理的?
代码示例#1
function countdown() {
let i; // note we declare let outside of the for loop
console.log("Countdown:");
for(i=5; i>=0; i--) {
setTimeout(function() {
console.log(i===0 ? "GO!" : i);
}, (5-i)*1000);
}
}
countdown();
代码示例#2
function countdown() {
console.log("Countdown:");
for(let i=5; i>=0; i--) { // i is now block-scoped
setTimeout(function() {
console.log(i===0 ? "GO!" : i);
}, (5-i)*1000);
}
}
countdown();
答案 0 :(得分:0)
在示例1中,变量在函数内部声明。每次调用i
时,您都会获得新的countdown()
。在countdown()
范围内,变量发生变化。到超时运行时,i
将处于其最低值。
在示例2中,变量在循环内部声明。每次循环时你都会得到一个新的i
。这意味着您为传递给i
的每个函数都获得了新的setTimeout
。不同的超时不再共享相同的变量。
答案 1 :(得分:-1)
关键区别在于在for循环中使用let
关键字。
在代码示例#1中,在for循环之外声明i
。这意味着每个闭包中对i
的每次访问都会导致相同的i
被解除引用,因为i
在每个闭包的相同块范围内,这就是我们获得-1
的原因。每一次。
在代码示例#2中,在for循环中声明了i
,这意味着为每次执行创建了 new i
。每个闭包在for循环中引用它自己的独占块,它具有唯一的i
。因此,我们得到预期的5比1倒计时。
对于let
等ES6功能的使用,使用Babel REPL确定应用范围规则的方式非常方便。以下简化版本的代码块#1和#2:
for (var j = 0; j < 5; ++j) {
setTimeout(function() { console.log(j); }, 1);
}
for (let i = 0; i < 5; ++i) {
setTimeout(function() { console.log(i); }, 1);
}
...编译成:
"use strict";
for (var j = 0; j < 5; ++j) {
setTimeout(function () {
console.log(j);
}, 1);
}
var _loop = function _loop(i) {
setTimeout(function () {
console.log(i);
}, 1);
};
for (var i = 0; i < 5; ++i) {
_loop(i);
}
请注意,对于代码块#2,i
如何使用_loop
函数复制到不同的函数作用域,其中每个闭包引用其自己的i
。