一、什么是闭包
闭包是一个函数,它有权访问另一个函数作用域中的变量。
JavaScript中,函数内部定义的变量,都可以看作私有变量,函数外部无法直接访问。闭包就是有权访问另一个函数作用域中的变量的函数。
创建闭包的常用方式,就是在一个函数内部创建另一个函数,并作为返回值。
function fun(){
var name = 'latency';
return function(){
console.log(name);
}
}
var result = fun();
result(); //latency
内部函数(一个匿名函数)可以访问外部函数中的变量name。即使这个函数被返回了,在其它地方被调用了(result();),但它仍可以访问name,是因为内部函数的作用域链包含fun()的作用域。当fun()函数在执行完毕后,其活动对象不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象。
二、闭包与变量
闭包只能取得包含函数中任何变量的最后一个值。
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(){
return i;
};
}
return result;
}
上面的函数,本应返回0~9,但实际上每个都返回10。因为for循环中每个函数的作用域链中都保存着createFunctions()函数的活动对象,它们引用的都是同一个变量i,在createFunctions()函数返回后,i的值为10。
可以通过创建一个匿名函数强制让闭包的行为符合预期:
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(num){
return function(){
return num;
};
}(i); //立即执行,按值传递,将i的值赋给num
}
return result;
}
三、闭包的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"(实际上调用闭包的是window)
每个函数在被调用的时候都会自动取得this和arguments两个对象。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不能直接访问外部函数中的这两个变量。
解决办法就是把外部作用域中的this变量保存在一个闭包能直接访问到的变量里:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); //"MyObject"