for循环中用let声明的变量每次都是新变量

在 let 出现之前,for 循环定义的迭代变量会渗透到循环体外部:
for (var i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // 5
改成使用 let 之后,这个问题就消失了,因为迭代变量的作用域仅限于 for 循环块内部:
for (let i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // ReferenceError: i 没有定义
在使用 var 的时候,最常见的问题就是对迭代变量的奇特声明和修改:
for (var i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 你可能以为会输出 0、1、2、3、4
// 实际上会输出 5、5、5、5、5
之所以会这样,是因为在退出循环时,迭代变量保存的是导致循环退出的值:5。在之后执行超时
逻辑时,所有的 i 都是同一个变量,因而输出的都是同一个最终值。
而在使用 let 声明迭代变量时,JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量
每个 setTimeout 引用的都是不同的变量实例,所以 console.log 输出的是我们期望的值,也就是循
环执行过程中每个迭代变量的值。
for (let i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 会输出 0、1、2、3、4
引自:3.3.3  【const声明】
 
这里提到了let生命迭代变量时,JS引擎会在后台为每个迭代循环声明一个新的变量,根据怎么理解for循环中用let声明的迭代变量每次是新的变量?这篇文章中的介绍,
 
在使用var定义变量i时,
for (var i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0);
}
在去糖(desugar)后执行的模拟代码为:
// 不需要加区块符,因为区块也不会影响
var i;
i=0;
if(i<5)
  setTimeout(() => console.log(i), 0);
  i++;
  if(i<5)
    setTimeout(() => console.log(i), 0);
    i++;
//...

在使用let定义变量i时,
// 用区块符区分每次循环的语句
// 每次for语句开始,i指定为一个全域刻度__status,这只是方便说明而已
// __status会记录for语句i最后的值
{ let i;
  i = 0;
  __status = {i};
}
{ let {i} = __status;
  if (i < 10)
      setTimeout(()=>console.log(i), 0);
      __status = {i};
}   
    { let {i} = __status;
      i++;
      if (i < 10)
          setTimeout(()=>console.log(i), 0);
          __status = {i};
    }
    //...


posted @ 2021-05-15 10:11  发条鸭  阅读(537)  评论(0)    收藏  举报