再谈闭包
2017-09-26 本文已影响15人
DCbryant
var fnArr = [];
for (var i = 0; i < 10; i ++) {
fnArr[i] = function(){
return i;
};
}
i = 5
console.log( fnArr[3]() ); //5
这里居然打出5,为什么不是10呢?为什么不是3呢?有很多人知道i引用的是全局变量i,可以用闭包解决这个问题,那么为什么会这样呢?还牵扯到了函数的执行原理,因为函数又是一个对象,对象会被存到堆内存中,所以函数当函数没有执行的时候,就把函数当做字符串放在堆内存中,数组中存储的,其实只是指向这个堆内存的指针,i并没有传进去,执行的时候i才被传进去
fnArr[0] = function(){
return i
}
fnArr[1] = function(){
return i
}
直到函数执行的时候浏览器才会解析这段字符串,把他当做函数来执行,所以当我们执行函数的时候,i已经循环到10了,i取到的就是全局变量10,之后我们把i赋值为5,i取到的就是5了。
这时候我们就发现一个问题,我们想取到每一个i值,怎么办呢?可以把它放到局部作用域,这时候就轮到闭包大展身手了,闭包的作用就是创建一个局部作用域,保存变量
所以有了之后的一系列的闭包写法
所以这个题的重点不在于闭包,而在于你对于函数执行了解的程度,如果你能完全理解为什么i变成10,而不是只知道i为10,那么之后写成闭包就是在自然不过的事了,因为你知道这段代码有什么问题,那么就只剩解决问题了,可是,程序员的天职不就是解决问题吗?
最后附一下解决办法:
方法1:
//自执行函数
var fnArr = [];
for (var i = 0; i < 10; i ++) {
fnArr[i] = function(i){
return function(){
return i;
}
}(i)
}
console.log( fnArr[3]() ); //3
方法2:
//自执行函数
var fnArr = [];
for (var i = 0; i < 10; i ++) {
fnArr[i] = (function(){
var temp = i
return function(){
return temp
}
})()
}
console.log( fnArr[3]() ); //3
方法3:
var fnArr = [];
for (var i = 0; i < 10; i ++) {
!function(i){
fnArr[i] = function(){
return i;
}
}(i)
}
console.log( fnArr[3]() ); //3
方法4:
var fnArr = [];
for (let i = 0; i < 10; i ++) {
fnArr[i] = function(){
return i;
};
}
console.log( fnArr[3]() ); //3