JS:什么是闭包

概念

闭包在JS中,实际上是不存在的,它只是一种马后炮式的总结。在自己写代码时,根本就不知道闭包,只是按照自己的思维来写的,最后,发现了某段代码符合闭包的定义。
如果一个函数用到了它外面的变量,那么这种做法就是闭包。

举例分析

比如我们在做一个游戏,某一个角色有30条命,在写还剩多少条命的代码时,可以用一个全局变量表示:

1
var lives = 30

在减少一条命后,把lives减去1即可,但这样做并不妥,任何人都可以改变这个全局变量的值,所以我们得让外面不能直接访问这个变量,得按我们自己规定的方法才能访问,不难想到可以用局部变量。只要我们在某个函数里声明这个变量,这个变量就是局部变量了。但是局部变量别人访问不到,你可以暴露一个函数,让别人可以间接访问。代码如下:

1
2
3
4
5
6
7
8
9
10
function xxx(){
var lives = 30
function die(){
lives -=1
return lives
}
return die
}
var a = xxx()
setInterval(function(){console.log(a())},1000)

这样控制台便会每秒钟打印出lives的值,是逐次减小的。通过这种函数调用的方法xxx()(),便可以让lives少一条命。这段代码里,函数die使用了其外部的变量,这就符合了闭包的定义。

闭包的谣言

有人认为闭包造成了内存泄漏?
这句话是不正确的。内存泄漏是指你用不到(访问不到)的变量,依然占据着内存空间,没有被再次利用起来。在上面的代码中,闭包里面的变量是我们要访问的变量,并不存在什么内存泄漏。
如果在上面代码中,xxx函数里再声明一个变量:

1
2
3
4
5
6
7
8
9
10
function xxx(){
var b = '1'
var lives = 30
function die(){
lives -=1
return lives
}
return die
}
xxx()()

在调用xxx()()后,xxx函数里的var b ='1',由于没有人使用,不存在值引用,那么这行代码会被浏览器回收掉。这样就不存在内存泄漏了。这也叫做垃圾回收。JS有一套它自己的垃圾回收机制,JS的解析器可以检测到何时不在使用这个对象了。当这个对象无用的时候,就把它占用的内存释放掉。
然而,IE浏览器以前却存在这个bug,它并不能回收掉那块无人指引的那块内存。
总之,浏览器会自动管理我们的内存,不需要担心什么内存泄漏。