javascript闭包

javascript闭包

闭包(closure)是Javascript语言的一个很有意思的东西,在很多高级的js应用或者js设计模型里面是需要经常使用他的。闭包已经是一个老话题了,网上一搜估计就有无数的文章介绍,闭包说句老实话我到现在都不敢跟大家说我百分百完全掌握了它,我今天还是站在一个刚入门的人,给大家简单谈谈我对javascript闭包的理解,希望对大家学习javascript会有帮助。


闭包(closure)用比较官方的话来说就是一个函数有权访问另一个函数作用域中的变量函数。(有些人肯定会说太坑爹了,这太官方了,俺听不懂)。那咱可以简单的理解为就是一个函数里面又嵌套了一个函数。

function A(){
    var cat = "猫";
    function B(){
        console.log(cat);//“猫”
    }
}

上面这段代码就是一个闭包函数了,函数B是可以访问函数A里面的变量cat。但是A函数如果想访问B函数里面的东西是不可以的。例如:

function A(){
    var cat = "猫";
    function B(){
        var dog  = "狗";
        console.log(cat);//“猫”
        console.log(dog);//“狗”
    }
    console.log(dog);//“dog is not defined”
}

上面的代码基本上展示了javascript作用域链的状态,里层的函数可以访问包裹在他外层函数里面的所有变量。但是外层函数却不能访问里层函数的东西。


其实上面的闭包函数还可以这么写:

function A(a){
    var cat = "猫";
    B(cat);
}
function B(a){
    var dog  = "狗";
    console.log(a);//“猫”
    console.log(dog);//“狗”
}

我们可以把函数B写在函数A外面,然后再A里面在调用这个函数B,同样可以实现刚的操作。这个A函数同样实现了闭包。


我们今天要讲的不仅仅是这个,闭包到底有什么特点?为什么越高级的应用,使用闭包越多?

好吧让我们先来看一个例子吧,下面的这个例子我们要达到的目的是点击li时,弹出当前点击的这个li是第几个li?


html代码:

<ul id="list">
    <li>第1行</li>
    <li>第2行</li>
    <li>第3行</li>
    <li>第4行</li>
    <li>第5行</li>
    <li>第6行</li>
</ul>


js代码

var $li = document.getElementById("list").getElementsByTagName("li");
var i=0;
for(;i < $li.length;i++){
    $li[i].onclick = function(){
        console.log(i);
    }
}

运行上面这段代码,你会发现无论你点击哪一行的li,最后的结果都是输出6,这到底是为什么呢,上面的for循环后i的最终值是6,他并没有一级一级的存储下来每个i,而是一次性输出了6给下面的$li[i],所以每次点击当然最后的i也只能是6。


大家可以看到上面的函数并没有使用到闭包的功能,那我们就来改造一下代码,让我们的js代码能够满足我现在的需求。

var $li = document.getElementById("list").getElementsByTagName("li");
function A(){
    var i=0;
    for(;i < $li.length;i++){
        B(i);
    }
}
function B(index){
    $li[index].onclick = function(){
        console.log(index);
    }
}
A();

运行下我们改造后的代码,你就会发现我们点击哪个li就显示当前点击的是哪一个li的值,不再是全都输出6了。


上面的代码实际上告诉了我们一件事情,就是闭包是可以储存变量的,即使A函数里面的变量i已经执行完毕,被javascript垃圾回收机制销毁了,但是B函数还会保存住这个值。


如果上面的代码你还没能理解,那没关系,我们再把上面代码分解的简单点:

var i=0;
for(;i < $li.length;i++){
    function test(){
        console.log(i);
    }
}
test();//输出的是6

上面这段代码大家肯定会觉得奇怪为什么只输出了6,而不是0,1,2,3,4,5呢?


我们看下上面的方法如果用闭包函数来做会不会输出0,1,2,3,4,5。

function A(){
    for(var i=0;i < $li.length;i++){
        B(i);
    }
}
function B(index){
    console.log(index);
}
A();//输出的是0,1,2,3,4,5


这样子的例子是不是就是我们想要的结果了,如果能理解上面的写的例子,我想你就大概就能对闭包能有个初步的理解和认识了,至于要在什么场景下使用,那就看你对他的理解程度了。


缺陷:

闭包当然也是有缺陷的,他的优点和缺点是共存的,他可以储存父函数的变量,即使是父函数的变量被javascript垃圾回收机制销毁了,但是闭包函数仍然储存着,这就造成了严重的内存问题了,这个时候只能通过我们自己手动来清楚内存中的值了。以上面的代码为例:

function A(){
    for(var i=0;i < $li.length;i++){
        B(i);
    }
}
function B(index){
    console.log(index);
}
A();//输出的是0,1,2,3,4,5
B = null;

这样子B函数中的内存就被释放了。


以上是我对javascript的一些浅解,希望对大家学习javascript有所帮助,如果以上言论有不对的地方,希望各位立即批评指出。在此表示感谢!


转载请注明来自 520UED http://www.520ued.com/article/53882648b992a7c43f5c2042

comments powered by Disqus