一、闭包有什么用
1、能够在函数外部引用函数内部的变量(变量作用域);
2、让变量的值始终保持在内存中(垃圾回收机制),避免全局变量的污染;
3、私有成员的存在。
二、为什么要引入闭包
在第一点说明了使用闭包的好处,备注里说明了使用闭包的原因。正是为了解决JavaScript变量作用域和垃圾回收机制所带来的问题耳引出的闭包。
1、变量作用域:
在JavaScript中,没有块级左右域,只有全局作用域和局部作用域,如下:
例1: 函数内部可以直接读取全局变量
var n=999;
function f1(){
alert(n);
}
f1(); // 999
例2: 函数外部无法读取函数内的局部变量
function f1(){
var n=999;
}
alert(n);// error
例3:函数内声明变量,没有使用var,相当于定义了全局变量
function f1(){
n=999;
}
f1();
alert(n);// 999
2、JS垃圾回收机制
JavaScript中,会按照固定的时间回收不再使用的变量,以释放其所占用的内存。通过闭包能够避免变量被回收。
三、如何使用闭包
1、在函数外部获取内部变量
例4:function f1(){
n=999;
function f2(){
alert(n);// 999
}
}
既然f2能够访问f1 中的所有变量,所以将f2作为返回值,便可 在f1外访问f1内的变量了,如例5:
例5:function f1(){
n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result();// 999
2、将变量保存在内存中,例6.
例6:
function f1(){
var n=999;
nAdd=function(){
n+=1
}
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result();// 999
nAdd();
result();// 1000
结果显示,它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
这是因为f1 和 f2 相互引用,f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
四、闭包例子
例7:
vari =5;
function a() {
var i =0;
function b() {
alert(i++);
}
return b;
}
a()(); //0
例8:
var name ='The Window';
var object1 = {
name:'My Object',
getNameFunc:function() {
return function() {
return this.name;
};
}
};
alert(object1.getNameFunc()()); //The Window
解释一下例8. object1.getNameFunc() 的结果是第一个return 的内容,object1.getNameFunc()() 实际上就相当于在全局环境下执行了第一个return 的内容,所以this 指向的是window, 所以this.name = window.name = 'The Window'.
例9:
a、
var data = [];
for (var i = 0; i < 3; i++) {
console.log('i:'+i);
data[i] = function () {
console.log(i)
}
}
data[0](); //3
data[1](); //3
data[2](); //3
b、
var data = [];
for(vari =0;i <3;i ++){
console.log('i:'+i);
data[i] = (function(i) {
return function() {
console.log(i);
}
})(i)
}
data[0](); //0
data[1](); //1
data[2](); //2
五、使用闭包的注意点
1、由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
注:顺便提一下内存泄漏和内存溢出的区别。
内存泄露:memory leak,指程序申请了内存但不归还,导致这些内存无法再配分配自己也无法使用。
内存溢出:out of memory,指内存不够用了。假如你定义了一个Interger,却给了一个 Long 的值,便会内存溢出。
在用户使用中,少量的内存泄露感觉不出,但内存泄露堆积后果很严重,将导致内存溢出。
2、闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便。
举个例子:
function aaa() {
var c =1;
return function() {
alert(c++);
};
}
var fun =aaa();
fun();//1
fun();//2
fun =null;//回收
var fun =aaa();
fun();//1
function aaa() {
var c =1;
return function() {
alert(c++);
};
}
aaa()();//1
aaa()();//1
var fun =aaa();
fun();//1
此篇文章参考自:(http://www.jb51.net/article/24101.htm)