for循环中let var的区别,从循环原理的角度去理解这个问题

我在前一篇讨论let与var区别的博客中,顺带一笔带过了let与var在for循环中的不同表现,虽然解释了是块级作用域的影响,但具体是怎么去影响的呢,我尝试的去理解了下,这篇博客主要从for循环步骤拆分的角度去理解两者的区别。

 一、一个简单的for循环问题与我思考后产生的问题

还是这段代码,分别用var与let去声明变量,得到的却是完全不同的结果,为什么?如果让你把这个东西清晰的讲给别人听,怎么去描述呢?

//使用var声明,得到3个3
var a = [];
for (var i = 0; i < 3; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[0](); //3
a[1](); //3
a[2](); //3
//使用let声明,得到0,1,2
var a = [];
for (let i = 0; i < 3; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[0](); //0
a[1](); //1
a[2](); //2

再弄懂这个问题前,我们得知道for循环是怎么执行的。首先,对于一个for循环,设置循环变量的地方是一个父作用域,而循环体代码在一个子作用域内;别忘了for循环还有条件判断,与循环变量的自增。

for循序的执行顺序是这样的:设置循环变量(var i = 0)  ==》循环判断(i<3)  ==》满足执行循环体 ==》循环变量自增(i++)

我们按照这个逻辑改写上面的for循环,以第一个var声明为例,结合父子作用域的特点,上面的代码可以理解为:

{
  //我是父作用域
  let i = 0;
  if (0 < 3) {
    a[0] = function () {
      //我是子作用域
      console.log(i);
    };
  };
  i++; //为1
  if (1 < 3) {
    a[1] = function () {
      console.log(i);
    };
  };
  i++; //为2
  if (2 < 3) {
    a[2] = function () {
      console.log(i);
    };
  };
  i++; //为3
  // 跳出循环
}
//调用N次指向都是最终的3
a[0](); //3
a[1](); //3
a[2](); //3

那么我们此时模拟的步骤代码中的声明方式var修改为let,执行代码,发现输出的还是3个3!WTF???

按照模糊的理解,当for循环使用let时产生了块级作用域,每次循环块级作用域中的 i 都相互独立,并不想var那样全程共用了一个。

但是有个问题,子作用域中并没有let,何来的块级作用域,整个循环也就父作用域中使用了一次let i = 0;子作用域哪里来的块级作用域?

请教了下百度的同学,谈到了会不会是循环变量不止声明了一次,其实自己也考虑到了这个问题,for循环会不会因为使用let而改变了我们常规理解的执行顺序,自己又在子作用域用了let从而创造了块级作用域?抱着侥幸的心理还是打断点测试了一下:

可以看到,使用let还是一样,声明只有一次,之后就在后三个步骤中来回跳动了。

二、一个额外问题的暗示

如果说,在使用let的情况下产生了块级作用域,每次循环的i都是独立的一份,并不共用,那有个问题,第二次循环 i++ 自增时又是怎么知道上一个块级作用域中的 i 是多少的。这里得到的解释是从阮一峰ES6入门获取的。

JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

 那这就是JS引擎底层实现的问题了,我还真没法用自己的代码去模拟去实现,我们分别截图var与let断点情况下作用域的分布。

首先是var声明时,当函数执行时,只能在全局作用域中找到已被修改的变量i,此时已被修改为3

而当我们使用let声明时,产生了block作用域,而且可以确定的是整个for循环let i只声明了一次,但产生了三个块级作用域,每个作用域中的 i 均不相同。

我的猜测,与JS引擎记录 i 的变换进行循环自增而我们却无法感知一样,JS引擎在let的情况下,每次循环自己都创建了一个块级作用域并塞到了for循环里(毕竟子作用域里没用let),所以才有了三次循环三个独立的块级作用域以及三个独立的 i。

这也只是我的猜测了,可能不对,如果有人能从JS底层实现给我解释就更好了。

那么说到这里大概说完了,好像还是没能很权威的说清楚,拆分步骤模拟for循环的方法无法解释let的情况,也许还有我考虑不够全面的地方,也欢迎有缘人指点。

虽然读完本文得到了一个猜测,但是也将for执行机制又理清了一遍不是吗。

猜你喜欢

转载自www.cnblogs.com/echolun/p/10584703.html
今日推荐