在es6的let const出现前,使用 for(var i=0;i<n;i++) 这种循环方式可能会出现问题,如图所示
个人理解:
在使用单步调试时发现
使用var声明时,js编译器会先var i=0,执行i<3判断,将值放入循环体内,然后执行i++自增
每次循环都会将function push到a这个数组内,循环结束后,a为三个function的数组
a[2]() return 的 i 实际上使用的是循环时var的 i,由于var的作用域问题,在循环时操作的 i 实际上是同一个,这就导致此处在获取 i 时实际上并不是获取的数组的下标1,而是获取的var的 i 的值,由于此时var的 i 的值等于3( 因为在循环体内循环的时候,i 经历了由0-2后再次执行了i++,此时i为3,且通不过i<3的判断,因而var 的 i 实际上的最终值为3 ),所以不论数组下标为多少,始终输出为 3。
而在let i 时,在每次执行循环时i实际上在一个块级作用域内,在每个块级作用域内 i 的值已经被固定下来,此时的a数组中的每个function实际上return的是他们块级作用域的 i ,所以在a[2]()时实际上return的 i 与数组下标依旧没有关系,之所以return的 i 是 2 ,是因为在a[2]()这个funtion的块级作用域内,i 的值为2,所以输出时为2。
总结一下:
个人认为,在理解这个问题时,不能认为调用a[2]()这个function时,i 的值为数组下标,否则就会陷入误区,实际上在数组的每个function内,return的 i 与数组下标没有关系,return 的 i 主要取决于在a[2]()这个函数作用域内的 i 的值,var 时 ,i 在每次循环时都操作的同一个,可以类比为一个全局变量,所以在 return 时调用的 i 也是同一个。let 则会将 i 化为块级作用域内的局部变量,每次return 的 i 实际上并不是同一个,这也是 let 和 var 的一个重要区别。
全文为个人观点,如果有不合适或者有错误的地方欢迎大家评论指正。