闭包
闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的常见的方式:在一个函数内部创建另一个函数,例如:
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 2;
}else{
return 0;
}
};
}
无论什么时候,在函数中访问一个变量时,就会从作用域链中搜索具有相应名字的变量,一般来讲,当函数执行完毕后,局部活动就会被销毁,内存中只保留全局作用域,但是,闭包的情况又不同。
在一个函数内部定义的函数会将包含外部函数的活动对象添加到它的作用域链中,因此,在createComparisonFunction()函数内部定义的匿名函数的作用域链中将会包含外部函数的活动对象。
在匿名函数从createComparisonFunction()中返回后,它的作用域链被初始化为包含createComparisonFunction()函数的活动对象和全局变量对象。这样,匿名函数就能访问在createComparisonFunction()中定义的所有变量。最重要的是,createComparisonFunction()函数在执行完毕后,其活动对象也不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象。直到匿名函数被销毁,createComparisonFunction()的活动对象才会被销毁。例如:
var compareNames = createComparisonFunction("name");
var result = compareNames({name:"Nichols"},{name:"Greg"});
compareNames = null;
将创建的比较函数保存在变量compareNames中,而通过compareNames设置为等于null,解除该函数的引用,就等于通知垃圾回收例程将其清除,随着匿名函数的作用域链被销毁,其他作用域也都安全地销毁了。
由于闭包会携带包含它的函数的作用域,因此过度使用闭包可能导致内存占用过多。
闭包与变量
闭包只能取得包含函数中任何变量的最后一个值。例如:
function createFunctions(){
var result = new Array();
for(var i = 0; i < 10; i++){
result[i] = function(){
return i;
};
}
return result;
}
这个函数会返回一个数组,但每个函数都返回10,因为每个函数的作用域中都保存着createFunctions()函数的活动对象,所以他们引用的都是同一个变量。
关于this对象
this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象,不过,匿名函数的执行环境具有全局性,因此this通常指向window。例如:
var name = "the window";
var object = {
name:"my object";
getNameFunc:function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); //"the window"
在定义匿名函数之前,我们把this对象赋值给了一个名叫that的变量,而在定义了闭包之后,闭包也可以访问这个变量,因为他是我们在包含函数中特意声明的一个变量。
var name = "the window";
var object = {
name:"my object";
getNameFunc:function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); //"my object"