在看阮老师的ECMAScript 6 入门 时遇到了这个问题。先贴代码 :
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
不理解为什么是10,书中是这样解释的。
变量i是var声明的,在全局范围内都有效。所以每一次循环,新的i值都会覆盖旧值,导致最后输出的是最后一轮的i的值。
先假设是覆盖了,那为什么是10,为什么不是9, 不是 i < 10 吗?
还有这个let的用法
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
let声明 i , 就得到了6,这是为什么啊?书中是这样解释的。
变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。
整理下问题 :
1.用var声明的为什么结果是10,就算不是6,也该是9啊,因为循环是从0-9.
2.用let声明的为什么是6?
简单点的方法来理解这个事,第一段代码沾到控制台,输出的是10.如果你再输入a[6]回车,你会发现输出的是一个
function() {
console.log(i);
}
这时候加上那句话你就能理解了吧,其实整个数组存储的都是这个function,而且由于i是全局的,都是一个值,所以无论是数组第几个元素输出的也肯定是一个数。
那么再来说下,为什么是10不是9?循环在判断i<10的时候执行循环体,大于或者等于都不执行。也就是说只要当i增长到10就不再执行循环体了,那么现在你差不多知道了吧,i从0增加到9分别往数组a中添加了10个元素。当i增加到10,等于10了,不符合条件,循环结束了。所以i等于10的时候没有执行循环体,但是i已经增加到10了。所以数组中最后的结果是
[
function() {
console.log(10);
},...//10个相同的function
]
楼上说的对,你的基础确实不怎么好。作用域不明白可以理解,乱乱的。但是循环这块不应该,这个必须要会的。
var 的作用域 是函数作用域
let 的作用域 是 {}
建议 先别学 ECMAScript 6 了, 基础先打好
1 这个问题跟var let没关系,10是因为循环到9以后,js并不知道循环结束了,还会进行下一次循环,i加一等于10,然后判断条件发现不满足,才跳出循环。
2 var i你想象成全局变量,每次循环修改的、函数里面console.log访问的,都是同一个i。a[6]()是在循环结束后执行的,这时候的i由第一问知道是10。
let i你想象成局部变量,每次循环都生成一个新的,函数里面console.log访问的也都是不同的i。下面这段代码可能对你有点绕,但理解后对你学习js的变量很有帮助:
`
for (var i=0;i<10;i++) {
a[i]=(function(i){
return function() {
console.log(i);
})(i);
}
a[6](); // 6
`
循环变量i传到一个立即执行函数里,变成了局部变量i(其实这个函数的参数可以任意取名,取成i为了加深你的理解),在这个局部变量的作用域内定义了一个函数引用了它,js就会把它作为函数的上下文保存起来,所以console.log得到的是0到9不同的值。
我来解答一下var那一段你不理解i为什么是10的问题。
这其实很基础,如果i是9,那么for的判断条件 i < 10 是满足的,就还会执行循环体,然后再次i++,这时候i就是10了。
然后let那一段,为什么是6?
因为代码调用的就是第六个啊 a[6]();
,因为这里的i是局部变量,不会出现上面所说的覆盖问题,所以你调用的是第几个,就会输出第几个。