JS 闭包

一个你可能觉得很奇怪的现象

    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

 

posted @ 2014-06-24 14:15  cart55free99  阅读(170)  评论(0编辑  收藏  举报