再谈闭包

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
上一篇下一篇

猜你喜欢

热点阅读