首页 > 代码库 > JS 闭包

JS 闭包

一个你可能觉得很奇怪的现象
var batch = [];
var i = 0;
for(;i < 5; i++){
batch.push(function closureFn(){
console.log(i);
});
}

batch.forEach(function(item){item();console.log("<"+i+">")});
输出
5
<5>
5
<5>
5
<5>
5
<5>
5
<5>
输出的值都是i最后的结果

这个函数做的事情是向push数组中存放元素 这个元素是函数 且函数没有执行
所以输出一下batch得到
[function closureFn(){
console.log(i);
}, function closureFn(){
console.log(i);
}, function closureFn(){
console.log(i);
}, function closureFn(){
console.log(i);
}, function closureFn(){
console.log(i);
}]

对batch的每一项进行遍历
forEach中的item就是
function closureFn(){
console.log(i);
}这个函数
故item() 运行的话就是输出最终的i值

PS batch这个数组中的forEach的回调函数中变量i是全局变量i

 

或者用这个例子
var batch = [];
var i = 0;
for(;i < 5; i++){
batch.push(function closureFn(){
return i;
});
}
batch.forEach(function(f){console.log(f())});
得到5个5
这也是同样的道理

 

//使用立即执行函数来解决这个问题
var batch = [];
var i = 0;
for(;i < 5; i++){
batch.push(function closureFn(i){
console.log(i+" .. ");
return i;
}(i));
}
console.log(batch); //[0, 1, 2, 3, 4]

或者这样 加深印象
var batch = [];
var i = 0;
for(;i < 5; i++){
batch.push(function closureFn(index){
return function(){ console.log(i+" "+index)};
}(i));
}
batch.forEach(function(item){item()});

输出结果
5 0
5 1
5 2
5 3
5 4

这里使用了立即执行函数 所以每一次循环参数index得到的都是该轮循环的index
PS index不是i的引用 而是每次循环的时候i将自己的值传给index
closureFn这个函数立即执行 并且返回一个函数 这个返回的函数就是batch中的一个元素


PS 闭包中保存的是外部变量的引用而非值
所以for循环执行完后 i的值就已经是5 forEach每一项 在执行返回函数的时候i就是5