由于var
您有一个函数作用域,并且所有循环迭代只有一个共享绑定 - 即i
在每个 setTimeout 回调中意味着在循环迭代结束后最终等于 6的相同变量。
有了let
块作用域,当在for
循环中使用时,每次迭代都会获得一个新绑定 - 即i
在每个 setTimeout 回调中意味着一个不同的变量,每个变量都有不同的值:第一个是 0,下一个是1 等
所以这:
(function timer() {
for (let i = 0; i <= 5; i++) {
setTimeout(function clog() { console.log(i); }, i * 1000);
}
})();
与仅使用 var 等效:
(function timer() {
for (var j = 0; j <= 5; j++) {
(function () {
var i = j;
setTimeout(function clog() { console.log(i); }, i * 1000);
}());
}
})();
使用立即调用的函数表达式以类似于块作用域在示例中使用的方式使用函数作用域let
。
它可以不使用j
名称而写得更短,但也许它不会那么清楚:
(function timer() {
for (var i = 0; i <= 5; i++) {
(function (i) {
setTimeout(function clog() { console.log(i); }, i * 1000);
}(i));
}
})();
甚至更短的箭头函数:
(() => {
for (var i = 0; i <= 5; i++) {
(i => setTimeout(() => console.log(i), i * 1000))(i);
}
})();
(但如果您可以使用箭头函数,就没有理由使用var
.)
这就是 Babel.js 如何将您的示例转换let
为在let
不可用的环境中运行:
"use strict";
(function timer() {
var _loop = function (i) {
setTimeout(function clog() {
console.log(i);
}, i * 1000);
};
for (var i = 0; i <= 5; i++) {
_loop(i);
}
})();
感谢Michael Geary在评论中发布了 Babel.js 的链接。查看实时演示的评论中的链接,您可以在其中更改代码中的任何内容并立即观看翻译。看看其他 ES6 特性是如何被翻译的,这很有趣。