Why let and var bindings behave differently using setTimeout function?
本问题已经有最佳答案,请猛点这里访问。
此代码记录
1 2 3 4 5 | (function timer() { for (var i=0; i<=5; i++) { setTimeout(function clog() {console.log(i)}, i*1000); } })(); |
但是这个代码…
1 2 3 4 5 | (function timer() { for (let i=0; i<=5; i++) { setTimeout(function clog() {console.log(i)}, i*1000); } })(); |
…记录以下结果:
1 2 3 4 5 6 | 0 1 2 3 4 5 |
为什么?
是因为
使用
使用
因此:
1 2 3 4 5 | (function timer() { for (let i = 0; i <= 5; i++) { setTimeout(function clog() { console.log(i); }, i * 1000); } })(); |
仅使用var就等于:
1 2 3 4 5 6 7 8 | (function timer() { for (var j = 0; j <= 5; j++) { (function () { var i = j; setTimeout(function clog() { console.log(i); }, i * 1000); }()); } })(); |
使用立即调用的函数表达式使用函数作用域的方式与在使用
它可以不用
1 2 3 4 5 6 7 | (function timer() { for (var i = 0; i <= 5; i++) { (function (i) { setTimeout(function clog() { console.log(i); }, i * 1000); }(i)); } })(); |
甚至更短的箭头功能:
1 2 3 4 5 | (() => { for (var i = 0; i <= 5; i++) { (i => setTimeout(() => console.log(i), i * 1000))(i); } })(); |
(但如果您可以使用arrow函数,就没有理由使用
这就是babel.js如何将您的示例与
1 2 3 4 5 6 7 8 9 10 11 12 13 | "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特性如何被翻译也是很有趣的。
从技术上讲,这就是@rsp在他出色的回答中的解释。这就是我喜欢理解在引擎盖下工作的方式。对于使用
1 2 3 4 5 | (function timer() { for (var i=0; i<=5; i++) { setTimeout(function clog() {console.log(i)}, i*1000); } })(); |
您可以想象编译器在for循环中是这样运行的
1 2 3 | setTimeout(function clog() {console.log(i)}, i*1000); // first iteration, remember to call clog with value i after 1 sec setTimeout(function clog() {console.log(i)}, i*1000); // second iteration, remember to call clog with value i after 2 sec setTimeout(function clog() {console.log(i)}, i*1000); // third iteration, remember to call clog with value i after 3 sec |
等等
由于