JavaScript中的闭包
闭包就是指有权访问另一个函数作用域中的变量的函数。而创建闭包的常见方式,就是在一个函数内部创建另一个函数。
有了闭包之后,原本在外部函数调用结束之后应该销毁的变量对象并未被销毁,而可以在闭包中继续使用,这是闭包最重要的特性。
闭包由两部分组成,即为函数和创建该函数的环境。
例如创建一个闭包:
function func(){
var a=1;
return function(){
return a;
};
}
此时如果有 var b=func(); console.log(b());//1
由上述例子可以看出,闭包中可以访问到外部函数的变量a。闭包的作用域链既包含他自己的作用域,同时也有包含它的函数的作用域和全局作用域。所以,闭包会比其他函数占用更多的内存,谨慎使用闭包。
使用闭包的几个注意事项
如果有对闭包的引用,在最后一定要记得释放,不然闭包的作用域不会被释放。
因为在JS中,只有当一个对象不再被引用时,才会被垃圾回收机制回收,不然就会一直存在在内存中,导致内存浪费。如果有对必报的引用,使用完成之后,一定要记得通过null释放这部分内存空间。
闭包只能取得包含函数中任何变量的最后一个值
看这样一个例子:
function createArr(){
var result = new Array();
for(var i=0;i<10;i++){
result[i] = function(){
return i;
}
}
return result;
}
按照我们的设计,这个函数应该返回一个索引值的数组。但实际上,每个函数都返回10。 因为闭包所保存的是整个变量对象,而不是某个特殊的变量。所有的函数引用的都是同一个i,而createArr()函数返回后,而i的值是10。
当然这也有解决办法,可以创建另一个匿名函数,像这样:
function createArr() {
var result = new Array();
for(var i=0;i<10;i++){
result[i] = function(num){
return function(){
return num;
};
}(i);
}
return result;
}
此时闭包访问的是num,并且通过一个立即执行的匿名函数将结果赋值给result,此时可以得到我们所期望的值。
关于闭包的this对象
在闭包中使用this对象可能会有一些问题,因为匿名函数的执行环境具有全局性,但是也可能由于编写闭包的方式不同,导致this的指向让人混淆。
看一个例子:
var name = “The Window”;
var object = {
name:“My Object”,
getNameFunc : function(){
return function(){
return this.name;
}
}
}
alert(object.getNameFunc()()); //“The Window”
注意:每个函数在被调用时都会自动取得两个特殊的变量:this和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,所以永远不可能直接访问到外部函数中的这两个变量。不过可以将外部作用域中的this对象保存到一个闭包能够访问到变量中。可以在return function这句话之前,加入一句var that=this,再将最后返回的this.name修改成that.name,即可成功。
内存泄漏
如果闭包作用域链中保存着一个HTML元素,那么元素将永远无法被系统自动销毁。所以我们必须要手动将其设置为null来销毁该元素。
闭包的主要应用场合就是设计私有的方法和变量。
如需更详细的介绍,可阅读闭包的更多官方资料。
本文为个人学习总结,如有错误,欢迎指出。