1.什么是闭包?
a.通俗点讲就是函数嵌套函数
b.内部函数可以调用外部函数中的变量(局部变量和全局变量)和函数
如下代码:
function cat(miao){
var wang = 'wangwang!!!';
function dog(){
alert(miao + wang);
}
}
c.函数中的变量和参数在外部函数调用完毕的时候不会被垃圾回收机制从内存中释放(也就是说会长期驻扎在内存中)
注释:通常一般的函数在调用完毕后垃圾回收机制就会将变量分配的内存进行收回
如下案例:当执行完var mimi = cat();
的时候实际上cat()
函数已经执行完毕,如果垃圾回收机制执行的话,那mimi();
执行完毕的时候就不会弹出'wangwang'
,但是实际上这个结果执行出来了,说明在外部函数调用完毕的时候变量和参数没有被垃圾回收机制收回内存,而是驻留在内存中没有被释放。
function cat(){
var wang = 'wangwang!!!';
function dog(){
alert(wang);
}
return dog ;
}
var mimi = cat();
mimi();
2.闭包有什么应用?
a.避免全局变量的污染
如下代码:
var age = 99 ;
function person(){
age++ ;
alert(age);
}
person();//100
person();//101
alert(age);//101
上面的代码age变量就可以被外界调用就不符合条件,全局变量被污染了。同时程序为了提高性能,最好不要出现全局变量。修改代码使age变成局部变量,如下代码:
function person(){
var age = 99 ;
age++;
alert(age);
}
person();//100
person();//100
上面的代码虽然实现了变量的局部化,同时不能被外界调用age变量了,但是发现功能没有实现了,每次函数执行完毕一次age就被垃圾回收机制收回内存了,重新执行。所以不能满足程序中age年龄递增的需求。其实闭包可以做到这一点,如下代码:
function person(){
var age = 99 ;
return function(){
age++;
alert(age);
}
}
var bill = person();
bill();//100
bill();//101
alert(age);//age is not defined
上面这段代码用闭包实现了功能。但是发现这种函数写法是不是很别扭呢?我是这种感觉,其实我们还可以继续用JavaScript中的模块化代码将上述代码中的函数改写成表达式自执行的方式,就简便多了。改写代码如下:
var person = (function(){
var age = 99 ;
return function(){
age++;
alert(age);
}
})();
person();//100
person();//101
上述代码中出现一个新的写法就是函数自执行,什么是函数自执行呢?写法就是这样的(function(){})();
其中函数中的内容会自己执行。
b.私有成员的存在
其实上面的模块化代码还有一个好处就是可以对私有变量和私有函数进行封装在一个密闭的空间中,外部是无法访问的。如下代码:
var module = (function(){
var number = 66 ;
function increase(){
alert(++number);
}
function desc(){
alert(--number);
}
return {
cat:increase,
dog:desc
};
})();
module.cat();//67
module.dog();//66
其实大名鼎鼎的jQuery框架就采用了上面的模块化封装思想。
3.闭包有什么好处,使用的时候要注意什么?
a.索引值的问题
当点击li的时候显示li在ul中的索引,如下代码:
var objLi = document.getElementsByTagName('li');
for(var i = 0 ; i < objLi.length ; i++){
objLi[i].onclick = function(){
alert(i);
}
}
发现如果代码这样写的话,当点击的时候显示的都是ul中所有li的总和。根本不能显示li的索引。这样就可以用闭包进行改进,因为闭包可以封装局部变量不收外界影响,如下代码:
var objLi = document.getElementsByTagName('li');
for(var i = 0 ; i < objLi.length ; i++){
(function(i){
objLi[i].onclick = function(){
alert(i);
}
})(i);
}
当然还可以像下面这样进行封装代码:
var objLi = document.getElementsByTagName('li');
for(var i = 0 ; i < objLi.length ; i++){
objLi[i].onclick = (function(i){
return function(){
alert(i);
}
})(i);
}
b.IE下引发内存泄露问题
如下代码:
var objDiv = document.getElementById('divOne');
objDiv.onclick = function(){
alert(objDiv.id);
}
就是像上面这段代码会引发内存泄露,为什么呢?因为在点击事件中引用外部对象,外部对象在函数执行完毕的时候内存无法释放,怎样解决这个IE下的问题呢?
var objDiv = document.getElementById('divOne');
var id = objDiv.id;
objDiv.onclick = function(){
alert(id);
}
objDiv = null ;
在上面的代码中就是讲变量局部化,然后用完对象进行手动设置为null进行内存释放。这样问题就可以解决了。