为什么让set和var绑定使用setTimeout函数表现不同? [英] Why let and var bindings behave differently using setTimeout function?

查看:166
本文介绍了为什么让set和var绑定使用setTimeout函数表现不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此代码记录 6 ,6次:

(function timer() {
  for (var i=0; i<=5; i++) {
    setTimeout(function clog() {console.log(i)}, i*1000);
  }
})();

但这段代码......

But this code...

(function timer() {
  for (let i=0; i<=5; i++) {
    setTimeout(function clog() {console.log(i)}, i*1000);
  }
})();

...记录以下结果:

... logs the following result:

0
1
2
3
4
5

为什么?

是因为以不同的方式绑定每个项目的内部范围, var 保持的最新值

Is it because let binds to the inner scope each item differently and var keeps the latest value of i?

推荐答案

使用 var ,您有一个功能范围,只有一个共享所有循环迭代的绑定 - 即每个setTimeout回调中的 i 意味着 最终相同的相同的变量在循环迭代结束后到6。

With var you have a function scope, and only one shared binding for all of your loop iterations - i.e. the i in every setTimeout callback means the same variable that finally is equal to 6 after the loop iteration ends.

使用 你有一个块范围当在中用于循环时,你会得到每次迭代的新绑定 - 即每个setTimeout回调中的 i 意味着一个不同的变量,每个变量都有不同的值:第一个是0,即下一个是1等。

With let you have a block scope and when used in the for loop you get a new binding for each iteration - i.e. the i in every setTimeout callback means a different variable, each of which has a different value: the first one is 0, the next one is 1 etc.

所以这个:

(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);
    }());
  }
})();

使用立即调用的函数表达式来使用函数作用域,其方式与示例中的块作用域类似使用

using immediately invoked function expression to use function scope in a similar way as the block scope works in the example with let.

如果不使用 j name,但也许它不会那么清楚:

It could be written shorter without using the j name, but perhaps it would not be as clear:

(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 。)

(But if you can use arrow functions, there's no reason to use var.)

这是Babel.js用来运行你的例子的方式来运行在不可用的环境中:

This is how Babel.js translates your example with let to run in environments where let is not available:

"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功能如何被翻译也很有趣。

Thanks to Michael Geary for posting the link to Babel.js in the comments. See the link in the comment for a live demo where you can change anything in the code and watch the translation taking place immediately. It's interesting to see how other ES6 features get translated as well.

这篇关于为什么让set和var绑定使用setTimeout函数表现不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆