daily-interview / fe-interview

:smiley: 每日一道经典前端面试题,一起共同成长。
https://blog.csdn.net/u010494753
MIT License
172 stars 22 forks source link

let和var在for循环中有什么不同? #32

Open artdong opened 4 years ago

artdong commented 4 years ago

let和var在for循环中有什么不同?

artdong commented 4 years ago

var函数作用域

// 函数
function a(){
    var i = 0;
    console.log(i) // i = 0;
}
console.log(i) // i is not define
// 块
{
    var j = 0;
    console.log(j)  // j = 0
}
console.log(j)  // j = 0;

上面可以看见,在函数中var声明的变量在函数外面是访问不到的,而在块中通过var声明的变量在块外面是能访问的,这就是说var是函数作用域,只有函数能约束他的作用范围,而代码块是做不到约束var定义变量的范围的。

let块级作用域

// 和var声明变量的例子比较
{
    let i = 0;
    console.log(i)  // i = 0;
}
console.log(i) // error

var、let在for循环中的表现

for(var i = 0;i<10;i++){
    setTimeout(function(){
        console.log(i)
    },100)
}  // 输出全是10

输出全是10的原因是因为i是全局变量,最后访问的都是全局变量i,而每次循环改变i的值就是改变全局变量的值,故而输出值均为10

之前对于这种问题的解决办法是通过闭包来实现

for(var i = 0;i<10;i++){
    (function(){
        var j = i;
        setTimeout(function(){
            console.log(j);
        },100)
    }())
}  // 输出0123456789;

上面解决办法的闭包实现,其实就是通过函数来构建一个作用域,每个作用域存储不同的i值,然后异步调用的函数是通过作用域链的调用规则访问到他创建时所在作用域的变量,就是创建时j的值,而j的值是局部变量,所以就能打印出0123456789

for 循环中使用let

for(let i = 0;i<10;i++){
    setTimeout(function(){
        console.log(i)
    },100)
}  // 0123456789;

为什么使用let就成了这个样子呢,就是因为let是块级作用域。因为每次循环都创建一个块级作用域,并且存上i的值,这里面的let定义的i值就是局部变量,所以每次循环改变的就是对局部变量赋值,访问也是根据作用域链规则访问局部变量i这样就得到了最后的结果。

思考题:请写出答案

let i = 0;
for(;i<10;i++){
    setTimeout(function(){
        console.log(i)
    },100)
}