题目:
var funcs = []
for (var i = 0; i < 10; i++) {
funcs.push(function() { return i; })
}
funcs.forEach(function(func) {
console.log(func());
})
这题输出多少呢?
答案:十个10。
为什么?
当然了,不排除已经会的童鞋了,如果会的话,请关闭这篇博文,不然只会浪费时间。如果不会,那么请务必好好看看。
回答之前,我们再看看这道题变化后输出是什么样子的:
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push(function() { return i; })
console.log(funcs[i]());
}
funcs.forEach(function(func) {
console.log(func());
})
那么这道题的打印的又是些什么值呢?
答案:0.1.2.3.4.5.6.7.8.9和十个10.
为什么呢?
其实大家把两段代码用浏览器即可验证出来了,细心的同学甚至就知道为什么了。
下面我把两段代码在浏览器中打印的值的图放出来:
1.首先,函数或者说方法只有在调用的是时候才会执行其内部语句,否则相当于只定义了一个方法,这里举个栗子:
这里我在里面定义了一个名为test的函数,但是里面的变量tested根本就未定义,但是在浏览器中是不会报错的,但只要我们调用了这个函数,那么浏览器会报错:
2. 知道之后,我们便可知原题中,由于funcs数组Push进去了十个匿名函数,但由于尚未调用,所以里面的i并未打印出来,但是实质上里面的i的确是0,1,2,3,4,5,6,7,8,9。但是在for循环外面在调用数组中的函数时,是因为在for循环体外,出了for循环的作用域,作用域这里我就不再解释了,所以导致后面在调用的时候,i的已经变成了for循环结束之后的值了,也就是10,也因此打印出十个10.
3.修改后的代码也就是第二段代码为什么打印的是0,1,2,3,4,5,6,7,8,9,是因为它在for循环体内,在作用域内,因此能访问到正确的i值。
好,分析完了,那么我们有什么方法可以修改原题之后,达到我们想要的效果,也就是分别打印出0,1,2,3,4,5,6,7,8,9呢?
博主这里提供两种:
1)ES5的方法:立即调用函数方法
// ES5知识,我们可以利用“立即调用函数”解决这个问题
var funcs = []
for (var i = 0; i < 10; i++) {
funcs.push(
(function(value) {
return function() {
return value;
}
})(i)
)
}
funcs.forEach(function(func) {
console.log(func())
})
2)ES6的方法:
const funcs = [];
for (let i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i)
})
}
funcs.forEach(func => func())