先来看一下var和let的区别,var的作用域更广,而let属于块级作用域:
for(var i=0;i<5;i++){};
console.log(i);
这里可以打印出i
for(let i=0;i<5;i++){};
console.log(i);
这里不可以打印出i,因为i在函数作用域里面。
以上就是最基本的区别,于是,我们再来看一道面试题
for(var i=0;i<5;i++){
setTimeout(function(){
console.log(i);
},1000)
}
console.log(i);//555555
通常,你以为这不就是一个for循环吗?结果肯定是123456了,但是却发现答案是5555555,这是什么原因呢?原因就在setTimeout里,setTimeout是个异步函数,里面的this指向window,以及他会在for循环加载完之后,才会执行,当for循环加载完了时,i也就等于5了。所以会输出555555.怎么避免这个情况呢?于是我们这样写
for (var i = 0; i < 5; i++) {
(function(i) {
setTimeout(function() {
console.log(i);
}, 1000);
})(i);
}
console.log(i);//501234
使用立即调用,便可以达到这个效果了。但是呢,还有一个更简便的方法,那就是采用let
for(let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 1000)
}
console.log(i);//501234
结果会是501234,setTimeout会延时触发,所以会先输出最后一个。
这里摘抄官网一段话:
当let声明出现在循环体里时拥有完全不同的行为。 不仅是在循环里引入了一个新的变量环境,而是针对每次迭代都会创建这样一个新作用域。 这就是我们在使用立即执行的函数表达式时做的事,所以在setTimeout例子里我们仅使用let声明就可以了。