要了解闭包,必须先从变量的作用域说起。
变量的作用域分为全局变量和局部变量;
在所有函数之外的变量成为全局变量,它的作用域为整个程序,即整个代码都可以调用它;
例如:
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中可能导致内存泄漏。解决方法是,在退出函数之前,将不使用的局部变量全部删除。