要了解闭包,必须先从变量的作用域说起。
变量的作用域分为全局变量和局部变量;
在所有函数之外的变量成为全局变量,它的作用域为整个程序,即整个代码都可以调用它;
例如:
var n=999;
function ff(){
alert(n);
}
ff();//999
函数内部的变量称为局部变量,它的作用域仅限于函数内部,即只能在函数内部调用,离开该函数后是无效的,在使用就会报错。
例如:
function f1(){
var n=999;
}
alert(n);//error
如果我们要使用其他函数内部的变量呢?
那就要使用闭包!
闭包的概念:就是能使用别人的局部变量。
常见的闭包:在函数里面再嵌套一个函数
因为在JavaScript语言中,只有函数内部的子函数才能读取这个函数的局部变量,因此可以把闭包简单理解为”定义在一个函数内部的函数“。所以在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
下面看一些简单的闭包例子:
function a(){
var b=10;
function data(){
b++;
return b;
}
return data();
}
var c=a();
console.log(c); //11 data()函数使用了父函数的局部变量,即使用了别人的局部变量
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2();
}
f1(); //999 f2()使用了f1()的局部变量
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result();//999
此外,闭包的使用会使函数中的变量值保存在内存当中
function f1(){
var n=999;
nAdd=function (){
n+=1;
}
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result();//999 从这开始执行f1()函数,首先定义局部变量n,然后执行return f2,然后调用f2()函数。输出n,此时n=999
nAdd(); //调用了nAdd函数,使n+1。
result();//1000 从这可以看出当使用闭包调用了n时,n的值已储存在内存中,因此再调用f1()函数时,输出的n已变为n+1。
要注意判断作用域指向的变量对象是否相同:
function f1(){
var n=0;
return function (){
console.log(n++);
}
}
var f0=f1(),f2=f1();//分别给f1()定义了两个对象 对象不同,其存储的值不同
f0();//0
f0();//1
f2();//0
那么,为什么f0()输出的值为0而不是1呢,原因是后置++是先返回值再进行加1运算。而前置++是先进行加1运算再返回值。
我们将上题的后置++,换成前置++尝试运行一下:
function f1(){
var n=0;
return function (){
console.log(++n);
}
}
var f0=f1(),f2=f1();
f0();//1
f0();//2
f2();//1
果不其然,如上所说。
闭包使用的注意点:
由于闭包会使得函数中的变量都保存在内存中,内存消耗很大,所以要避免闭包的滥用,否则会造成网页的性能问题,在IE中可能导致内存泄漏。解决方法是,在退出函数之前,将不使用的局部变量全部删除。