javascript闭环机制的详解

js的闭包是老生常谈的问题了,网上大部分的解释都不是特别易懂。在我看来,解决一个碰到的问题有两个思路:一是找到解决这个问题的方法。二是尝试从根源上去解析这个问题,以避免被其他类似的问题困扰。

下面我说说第一种思路。
咱们先看一个简单的例子:

var arr=[];
function eg(){
    for (var i= 0;i<3;i=i++){
        arr[i]=function(){
            alert(i)
        }
    }
};
arr();

正常情况下,我们希望能按照for循环的顺序依次弹出0,1,2。但实际上却是弹出了3次3。为什么会发生这种情况,咱们在这暂且不谈,在这个思路里只谈咱们解决这种情况,那就是加上立即执行函数。

var arr=[];
function eg(){
    for (var i= 0;i<3;i=i++){
        (function(){
        var temp = i;
        arr[i]=function(){
            alert(temp); //弹出0,1,2,3
        })();
    }
};
arr();

之后它就能正确达到咱们想要的效果了。如果你有一批动态生成的div或者其他元素,那么就可以在aarr[i]=function(){}这个方法里用jquery动态改变元素,或者说实现,点击某个div,再行后台获取这个div对应的值来渲染到这个div中,比如说:

var arr=[];
function eg(){
    for (var i= 0;i<3;i=i++){
        (function(){
        var temp = i;
        arr[i]=function(){
            alert(temp); //弹出0,1,2,3
             $("#id" + p).css("color", "white");
        })();
    }
};
arr();

ok,现在来谈谈第二种思路。想要解析闭包的根源,就不得不谈谈js的几个重要的特性:作用域链以及内存回收机制。

什么是作用域链?
简单来说,就是当函数在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。何为有序?比如说有三个for循环,他们在各自的循环里都定义了一个局部变量,假设从外到内是a,b,c。对于最里面的那层循环来说,它的作用域链就是 c到b到a到全局变量。

什么是内存回收机制?
和java一样javascript也是自动回收机制,把不再使用的内存回收。什么情况下不再使用呢?比如说在一个函数中定义的局部变量,在这个函数执行完毕后它就被销毁了。但是当你在一个函数中定义了另一个匿名函数,并在里面定义了一个局部变量,在这个匿名函数外部又调用了这个内部的局部变量,这时回收机制就不会生效,直到这个闭包彻底失效。

所以闭包的根本用途,其实就在于让一个函数内部的函数可以调用上一层环境声明的局部变量,方法就是立即执行函数。

有趣的是,在我遇到这个问题不就后我又碰到一个类似的情况,
那就是settimeout( )函数。使用场景是,处于某种需要,我想将一个for循环遍历的时间缩短,然后直接在for中加入了settimeout后发现打印的是乱码,这与之前的闭包问题有异曲同工之妙。

为什么会这样呢?因为js是单线程的执行顺序,而settimeout()却是一个异步的方法。如下:

var a=[1,2,3];  
        var len=a.length;  
        for(i=0;i<len;i++){  
            setTimeout{function(){  
                console.log(i);  
            },100}  
        }  

会打印3个undefined。但是修改一下代码

var a=[1,2,3];  
        var len=a.length;  
        for(i=0;i<len;i++){  
            setTimeout{function(){  
                console.log(i);  
            },**i*100**}  
        }  

就可以正确的log出来了。

两种思路没有孰优孰劣,只要能带给你思考,就值得肯定。

猜你喜欢

转载自blog.csdn.net/dk2290/article/details/78833697