在js中是没有块级作用域的,所以在后面的es6中有了let这个证明变量的方法来进行弥补。
大部分初学js的都会遇到这个问题
for (var i = 0; i < 2; i++) {
setTimeout(() => {
console.log(i);
})
}
他会一直输出2,而不是0,1,这是js中的异步问题。
而我们使用let声明时
for(let i=0;i<5;i++){
setTimeout(function(){console.log(i)})
}
就会正常输出,而大家有没有想过是为什么变为let就会好使。
for循环中初始化语句,是在循环开始之前要初始化这个变量。(这句话是犀牛书的原句)。
而如果在for循环外初始化let变量 ,那么let和var的效果一样的
let是块级作用域,let非常适合用于 for循环内部的块级作用域。js中的for循环体比较特殊,每次执行都是一个全新的独立的块作用域,使用let声明的变量作为迭代器变量传入到 for循环体的作用域后,不会发生改变,不受外界的影响。
这个时候问题就来了 let是块级作用域 而每次执行的循环都是一块独立的块作用域,那么下一个的循环是接收不到上一块的let定义的变量的,那么整个循环就都是有问题的。
所以for循环里的迭代器变量i let是每次都会声明一次的(这里的内容我查看了好多,网上有一带而过,我找了一些我认为比较靠谱的)就是每次循环都会进行一次的声明。
例子:
for(let i=0;i<3;i++)
{
}
拆分开来
{
let i=0;
}
{
let i=1;
}
{
let i=2;
}
例子2:
let arr = [];
for (var i = 0; i < 5; i++) {
arr[i] = function() {
console.log(i);
}
arr[0]();
}//0,1,2,3,4
这里的i为全局变量,用 var 声明时,变量 i 是唯一的,每一次 i 的改变都改变了自身的栈地址,每次调用函数都会去寻找i,所以是这样输出的。
例子3:
let arr = [];
for (var i = 0; i < 5; i++) {
arr[i] = function () {
console.log(i);
}
}
i = 8;
arr.forEach((total) => {
total(); // 8 8 8 8 8
});
我们在外面对i进行重新赋值,函数所输出的i又进行改变了。
例子4:
let arr = [];
for (let i = 0; i < 5; i++) {
arr[i] = function() {
console.log(i);
}
arr[0](); // 0 0 0 0 0
}
拆分
{
let i=0;
arr[i] = function() {
console.log(i);
}
arr[0]();
}
{
let i=1;
arr[i] = function() {
console.log(i);
}
arr[0]();
}
…
{
let i=4;
arr[i] = function() {
console.log(i);
}
arr[0]();
}
你会发现随着i的增加但是函数中的i值始终不变,能解释的只有块级作用域,即在每次循环里都let声明变量。随着变量 i 自增,数组第一项打印语句中的 i 却始终为 0。是因为第一项的 i 存放的栈地址不再改变,固定指向常量 0。数组其他项中 i 也各不相同,但一个变量不可能同时存放多个地址。
这就说明,数组每一项中 i 都是不同的,它们存放着不同的栈地址。每一次循环,都会有一个新的 i 来存放新的地址,每一个新的变量 i 都是基于上一个变量 i 。