闭包指词法表示包括不必计算的变量的函数,闭包函数能够使用函数外定义的变量。
闭包特性:
(1)、封闭性:外界无法访问闭包内的数据,如果在闭包内声明变量,外界是无法访问的,除非闭包主动向外界提供访问接口。
(2)、持久性:对于一般函数来说,在调用完毕后,系统会自动注销函数,而对于闭包来说,在外部函数被调用之后,闭包结构依然保存在系统中,闭包中的数据依然存在,从而实现数据的持久使用。
function f(x){
var a = x;
var b = function(){
return x;
}
return b;
}
var c = f(1);
alert(c()); //1
在上面示例中,首先在调用函数f结构体内定义两个变量,分别存储参数和闭包结构,而闭包结构中寄存着参数值。当调用函数f之后,函数结构被注销,它的局部变量也随之被注销,因此变量a中存储的参数值也随之丢失。但由于变量b储存着闭包结构,因此,闭包函数内部的变量值并没有被释放,在调用函数之后,依然能够用从闭包结构中读取到参数值。
闭包函数与普通函数主要包括以下类型的表示符:
函数参数(新参变量)、arguments属性、局部变量、内部函数名、this(指代闭包函数自身)。
this和arguments是系统默认的函数标识符,不需要特别声明,这些标识符在闭包体内的优先级是(左侧优先级大于右侧):this —> 局部变量 —> 形参 —>arguments —> 函数名。
例子:
1 function f(x){ //外部函数
2 var a = x; //外部函数的局部变量,并把参数值传递给它
3 var b = function(){ //内部函数
4 return a; //访问外部函数中的局部变量
5};
6 a++; //访问后,动态更新外部函数的变量
7 return b; //内部函数
8}
9 var c = f(5) //调用外部函数并赋值
10 alert(c()) //调用内部函数,返回外部函数更新后的值 6
第1步:程序变异之后,从第9行开始解析执行,创建上下文环境,创建调用对象,把参数、局部变量、内部的函数转换为对象属性。
第2步:执行函数体内代码。在第6行执行局部变量a的递加运算,并把这个值传递给对象属性a,内部函数动态保持与局部变量a的联系,同时更新自己内部调用变量的值。
第3步:外部函数把内部函数返回给全局变量c,实现内部函数的定义,此时c完全继承了内部函数的所有结构和数据。
第4步:外部函数返回后(即返回值调用完毕)会自动销毁,内部的结构、标识符和数据也会随之丢失。
第5步:执行第10行的代码命令,调用内部函数,此时返回的是外部函数返回时(销毁之前)保存的变量a所存储的最新数据值,既返回6.
如果没有闭包函数的作用,那么这种数据寄存和传递就无法得以实施。
例如:
function f(x){
var a = x;
var b = a; //把局部变量的值传递给局部变量b
a++
return b; //局部变量b
}
var c = f(5);
alert(c) //值为5
通过上面的示例可以很直观地看到,在没有闭包函数的辅助下,第8行代码执行后返回值并没有与外部函数的局部变量a最后更新的值保持一致。
闭包在程序开发中具有重要的价值,例如,使用闭包结构能够跟踪动态环境中数据的实时变化,并即使储存。
function f(){
var a = 1;
var b = function(){
return a;
}
a++;
return b;
}
var c = f();
alert(c()); //返回2,而不是1
在上面示例中,闭包中的变量a存储的值并不是对上面行变量a的值的简单复制,直到外部函数f调用返回。闭包不会因为外部函数环境的注销而消失,会始终存在。
<script language = ‘javascript‘ typt=‘text/javascript‘>
function f(){
var a = 1;
b = function(){
alert(a);
}
c = function(){
a++;
}
d = function(x){
a = x;
}
}
</script>
<button onclick = "f()">按钮1:(f())()</button><br/>
<button onclick = "b()">按钮2:(b = function(){alert(a);})()</button><br/>
<button onclick = "b()">按钮3:(c = function(a++;){alert(a);})()</button><br/>
<button onclick = "b()">按钮4:(d = function(x){a = x;})(100)</button><br/>
在上面示例中,在函数f中定义了3个闭包函数,它们分别指向寄存局部变量a的值,并根据不同的操作动态跟踪变量a的值。当在浏览器预览时,首先应该单击“按钮1”,调用函数f,生成3个闭包,3个闭包同时指向局部变量a的引用,因此,当函数返回时,这3个函数闭包都没有被注销,变量a由于被闭包引而继续存在。这时,如果继续单击按钮2和按钮4 ,那么会有没有在系统中生成闭包结构,而弹出编译错误。单击“按钮3”将动态递增变量a的值,如果此时单击“按钮2”,则会弹出提示值2.如果单击“按钮4”,则向变量a传值100,将动态改变闭包中寄存的值,如果此时点击“按钮2”,则会弹出提示值100。