let和var在for循环中的不同表现

var声明变量:

var只有函数作用域,没有块级作用域

//函数作用域的表现
function test(){
    var i =10;
    console.log(i); //10
}
test(); //10
console.log(i); // i is not defined;


//块级作用域对var没有约束
{
    var i = 10;
    console.log(i); //10
}
console.log(i); //10

从上面的代码可了解到,块级作用域对var是没有约束作用的。

 

let声明变量:

let与var不同,let是有块级作用域的。

//块级作用域对let声明的变量有约束
{
    let i = 10;
    console.log(i); //10
}
console.log(i) //ReferenceError

 

了解了上面的特性再来看看,var和let在for循环的一些不同表现:

//var声明i
function test(){
    for(var i=0;i<2;i++){
        setTimeout(()=>{
            console.log(i);
        },0);
    }
}
test();
//输出结果:2、2

//let声明i
function test(){
    for(let i=0;i<2;i++){
        setTimeout(()=>{
            console.log(i);
        },0);
    }
}
test();
//输出结果:0、1

可以看到只是声明方式不一样,输出的结果却有很大的差异。

在此之前还需要了解setTimeout()的执行机制:

setTimeout()是以异步的方式执行的。在执行for循环的时候,并不是执行一次for循环就立刻执行一次setTimeout(),而会让setTimeout()进入另一条线程进行等待,当主线程(这里就是test())执行完后,setTimeout()再依次执行。

 

在var中执行的时候:

因为var是没有块级作用域的,所以在for循环中声明的i会存在于test()函数作用域中。每一次for循环就会声明一次i,但后面声明的变量会覆盖前面声明的变量。所以当for循环执行完后(此时setTimeout()还未被执行),函数作用域中的i的值就变成2了

而setTimeout()所在的线程中是这样的:

//第一次进栈
setTimeout(()=>{
   console.log(i); 
});

//第二次进栈
setTimeout(()=>{
   console.log(i); 
});

这里的i都指向函数作用域中的i。所以输出都为2。

 

在let中执行的时候:

因为块级作用域的原因,let声明的i都会存在于for块级作用域中,每一次for循环都会生成一个块级作用域。所以setTimeout()在线程中是这样的:

{
  let i=0;
  setTimeout(()=>{
   console.log(i); 
  });    
}

{
  let i=1;
  setTimeout(()=>{
   console.log(i); 
  });    
}

所以会一次输出0,1;

posted @ 2019-07-18 17:15  半个小菜鸡  阅读(2663)  评论(0编辑  收藏  举报