一个你可能觉得很奇怪的现象
var batch = []; var i = 0; for (; i < 5; i++) { batch.push(function closureFn() { console.log(i); }); } batch.forEach(function(item){item()});
输出
5个5 值都是i最后的结果
先来看看上面一段代码都做了什么
这里循环做的事情是向push数组中存放元素 这个元素是函数
所以输出一下batch得到
[function closureFn(){
console.log(i);
}, ...]
最后对batch的每一项进行遍历并执行 故item() 运行的话就是输出i的值
既然如此为什么都是输出的5呢?
batch这个数组中的forEach的回调函数中变量i是全局变量i
所以for循环执行完后 i的值就已经是5 之后forEach每一项再执行的话 返回函数的时候i就是5
闭包也是同样的道理
function outer(){ var batch = []; var i = 0; for (; i < 5; i++) { batch.push(function closureFn() { console.log(i); }); } batch.forEach(function(item){item()}); } outer();
得到5个5 根据scope chain的原则 在执行closureFn这个函数中发现并没有变量i 所以会查找到父函数outer中的i
此时for循环已经执行完毕.. i的值就是5
PS 闭包引用了外部函数的变量 (引用!)
那么如何得到01234呢?
可以使用立即执行函数来解决这个问题
var batch = []; var i = 0; for (; i < 5; i++) { batch.push(function closureFn(index) { return index; }(i)); } console.log(batch); //[0, 1, 2, 3, 4]
这里使用了立即执行函数 所以每一次循环参数index得到的都是该轮循环的索引值
和前面不同 这里并没有把闭包(内部函数)直接赋值给数组 而是将该内部函数的执行结果赋值给数组
PS index不是i的引用 而是每次循环的时候i将自己的值传给index (传参的时候都是按值传递的)
数组中每个元素都有index变量的一个副本 因此就有01234
其他的博客:http://web.jobbole.com/82053/
更深刻的例子:http://www.cnblogs.com/cart55free99/p/3624489.html