一、闭包的概念
我们先来看一个简单的函数
function foo(){
var a=10;
return a;
}
foo();// 2
这里我声明了一个foo的函数,在该函数中有一个变量a,这个a属于局部变量,其作用域仅在函数中有效。
这里调用结束后,这里的局部变量是可以被释放(与js的垃圾回收机制相关)了,正常来说foo函数调用完毕,为局部变量a分配的空间就会被回收了。
我们稍微改动下上面的函数
function foo(){
var a=20;
return function(){
return a;
}
}
var func=foo();
func();// 20
这里我们可以看到foo函数的返回是一个匿名函数,而这个匿名函数返回的是局部变量a。当执行foo()后,这个局部变量是不会被回收的,这就形成了一个闭包,我们在外部仍然可以调用变量a。
我们来总结下。正常来说,函数内部的变量只能在该函数内使用,在函数外部是不能调用的,而闭包就是定义在函数内部的子函数,子函数中用到了父函数的参数或局部变量,局部在函数调用之后参数或者局部变量不会被回收,同时这个局部变量能在函数外部被调用到。(个人理解)
二、闭包的作用
那闭包的作用是什么呢?
1.具有封闭性,可以保护变量不被回收
function foo(){
var num=1;
function b(){
num++;
return num;
}
return b
}
var func=foo();
func();// 2
func();// 3
上面我们可以看到,在foo函数中有定义了一个子函数b,而这个子函数中使用了上一级(父函数)中的局部变量num,所以就导致foo()调用后,这个局部变量num不会被回收。foo()返回一个函数,赋值给了func,第一次调用func()返回num++后的值(num=2)这个时候num就会保存起来了,不会被回收,第二次调用func()返回num++值(在num=2的基础上,在加1,num=3)
2.避免全局变量污染
var a=1;
function foo(){
a++;
return a;
}
foo();// 2
foo();// 3
此时的a是全局变量,在程序中尽可能避免全局变量。那我们将变量a放到函数内试试
function foo(){
var a=1;
a++;
return a;
}
foo();// 2
foo();// 2
可以看到每一次foo()的执行结果都是2。这是因为变量a为foo函数的局部变量,每一次调用foo()完毕后,变量a都会被GC回收,下一次执行的时候,a又初始化为1,累加后输出2,所以永远输出的都是2
那有没有办法能使局部变量a既避免被全局污染又能做到不会GC回收呢?
答案是有的,我们可以利用闭包实现
function foo(){
var a=1;
function b(){
a++;
return a;
}
return b;
}
var func=foo();
func();// 2
func();// 3
三、使用闭包需要注意什么
(1)因为闭包会导致局部变量会保存在内存中,这对内存消耗是很大的,所以不能滥用闭包,否则会影响网页的性能,在IE中可能会导致内存泄漏。如何解决?
window.onload = function(){
var oDiv = document.getElementById('div1');
oDiv.onclick = function(){
alert(oDiv.id);
}
//当页面跳转的时候把oDiv.onclick引用置为空就好了
window.onunload = function(){
oDiv.onclick = null;
}
}
(2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象使用,把闭包当作它的公用方法,把内部变量当作它的私有属性,这时一定要小心,不要随便改变父函数内部变量的值
网友评论