闭包:
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数,仍以前面的
createComparisonFunction()函数为例
function createComparisonFunction(propertyName) {
return function(object1, object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if (value1 < value2){
return -1;
} else if (value1 > value2){
return 1;
} else {
return 0;
}
};
}
匿名函数中访问了外部函数的变量properName.即使这个内部函数被返回了,而在其他地方调用,但是她还是可以访问变量properName.因为内部函数的作用域链中包含了外部函数createComparisonFunction()的作用域链.
在闭包中,在另一个函数内部定义的函数会将外部函数的活动对象添加到它的作用域链中.因此,在这个例子中内部匿名函数的作用域中,实际上会包含外部函数的活动对象在匿名函数从createComparisonFunction()中被返回后,它的作用域链被初始化为包含createComparisonFunction()函数的活动对象和全局变量对象。这样,匿名函数就可以访问在createComparisonFunction()中定义的所有变量。更为重要的是,createComparisonFunction()函数在执行完毕后,其活动对象也不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象。换句话说,当createComparisonFunction()函数返回后,其执行环境的作用域链会被销毁,但它的活动对象仍然会留在内存中;直到匿名函数被销毁后,createComparisonFunction()的活动对象才会被销毁.
闭包与变量
闭包只能取得外部函数中变量的最后一个值.闭包所保存的是整个变量对象,而不是某个特殊的值.来看下面一个例子:
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(){
alert("i="+i);
return i;
};
}
result[0]();//i=10
return result;
}
在这里,并不是每个函数都返回自己的索引值,而是每个函数都返回10.因为每个函数的作用域链中都保存着createFunctions()的活动对象,所以他们引用的都是同一个i.当createFunctions()函数返回后,变量i 的值是10,此时每个内部函数都引用着保存变量i 的同一个变量对象,所以在每个函数内部i 的值都是10。
但是我们可以这样来让我们的函数符合我们认为的那样:
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(num){
return function(){
return num;
};
}(i);
}
return result;
}
在这个版本中,我们没有直接把闭包赋值给数组,而是定义了一个匿名函数,并将立即执行该匿名函数的结果赋给数组。这里的匿名函数有一个参数num,也就是最终的函数要返回的值。在调用每个匿名函数时,我们传入了变量i。由于函数参数是按值传递的,所以就会将变量i 的当前值复制给参数num。而在这个匿名函数内部,又创建并返回了一个访问num 的闭包。这样一来,result 数组中的每个函数都有自己num 变量的一个副本,因此就可以返回各自不同的数值了。
this对象和闭包
我们都知道this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this=window,而当函数被作为某个对象的方法调用时,this=那个对象.不过匿名函数的执行环境有全局性,所有它的this通常指向window.但是由于有时候编写闭包的方式不同,可能this会有不一样的表现.举个例子:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); //"The Window"(在非严格模式下)
在这里,当执行到内部函数的时候,虽然内部环境仍然在引用外部函数的活动变量,但是外部环境的执行环境已经被销毁.所以虽然内部函数可以访问到外部函数的变量,但是这里得this指向的不是外部函数对象,而是window.
如果希望闭包访问该对象,可以这样写:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); //"My Object"
我们把this对象赋值给了一个名叫that 的变量。而在定义了闭包之后,闭包也可以访问这个变量,因为它是我们在包含函数中特意声名的一个变量,而内部函数可以访问到外部函数的变量.