这里首先介绍一下闭包的概念,因为我们在很多地方都要用到闭包,尤其是在很多的高级应用上。
一、闭包的概念
闭包(closure)就是能够读取其他函数内部变量的函数。
在JavaScript中,只有在函数内部的子函数才能读取局部变量,所以可以把闭包理解成一个“定义在函数内部的子函数”。
从本质上来讲,闭包就是连接内部函数和外部函数的桥梁,我们应该学会理解这座桥梁的构造,才能更好地利用这座桥梁。
二、如何读取内部变量?
我们已经知道闭包就是能够读取其他函数内部变量的函数,那么该如何去读取内部的变量呢?
1、我们先来了解一下变量的作用域吧,因为先了解了变量的作用域才能够知道为什么我们需要用闭包去读取内部变量。
变量的作用域一般分为两种:全局变量和局部变量。
内部的函数可以读取全局变量,但是外部函数不可以读取局部变量。
eg:
var a=9;
function demo1(){
alert(a);
}
demo1();//9
function demo2(){
var a=9;
}
alert(a);//error
注意:内部声明变量时一定要用var,否则为全局变量。
function demo3(){
a=9;
}
demo3();
alert(a);//9
在js中我们往往需要用到函数的内部变量,那这个时候我们就可以在函数的内部,在定义一个函数:
function demo1(){
a=9;
function demo2(){
alert(a);//9
}
}
解释:在上述代码中,demo2()被包含在demo1()中,对于demo1()中的变量demo2()都是可用的,反之则不行。这就是JavaScript的“链式作用域”结构(chain scope)。
子对象会一级一级地往上寻找父级对象的变量,且可用,反之则不可以。
2、既然demo2()可以读取demo1()的局部变量,那么只要把demo2()当作一个返回值,就可以读取demo1()内部的变量了。
function demo1(){
a=9;
function demo2(){
alert(a);
}
return demo2;
}
var result=demo1();
result();//9
三、闭包的用途
闭包在两个地方用得最多:
①是前面提到的可以读取函数的内部变量。
②是让这些变量的值永远保持在内存中。
我们来看看下面的代码吧~~~~~~~~~~~~~~~~~~~~~~~
funciton demo1(){
var a=9;
add=function(){
a+=1;
}
function demo2(){
alert(a);
}
return demo2;
}
var result=demo1();
reault();//9
add();
result();//10
解释:在这里reault实际上就是闭包demo2()函数,一共运行了两次,第一次是9,第二次是10。这可以证明函数demo1()的局部变量a一直保存在内存中。
因为demo1()是demo2()的父函数,而demo2()被赋给了一个全局变量(因为返回demo2(),所以demo1赋值实际上是demo2赋值),导致demo2始终在内存中,由此可得demo1也在内存中,不会被垃圾回收机制(garbage collection)回收。
四、闭包的注意点
1、由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2、闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。