闭包
概念:通过函数字面量来创建的函数对象包含一个连到外部上下问的链接。简单来说,由于在JavaScript中,函数是对象,对象是属性的结合,而属性的值又可以是对象,则在函数内定义函数为理所当然,如果在函数func内部声明函数inner,然后在函数外部调用inner,这个过程就产生了一个闭包。
而作用域的好处却是,内部函数可以访问定义它们的外部函数的参数和变量。
1.闭包的特性
例子:
var outer=[];
function clouseTest(){
var array=["one","two","three","four"];
for(var i=0;i<array.length;i++){
var x={};
x.no=i;
x.text.array[i];
x.invoke=function(){print(i);} //①
outer.push(x);
}
}
调用clouseTest(); 遍历outer,得到的结果:
4,4,4,4
其实,在每次循环①处,只是厚茧了一个函数体为“print(i);”的函数对象。i=4时,循环结束。外部函数返回,调用的i一直是4.
解决方法:
var outer=[];
function clouseTest2(){
var array=["one","two","three","four"];
for(var i=0;i<array.length;i++){
var x={};
x.no=i;
x.text.array[i];
x.invoke=function(no){
return function(){
print(no);
}
} (i); //①
outer.push(x);
}
}
闭包允许你引用存在于外部函数中的变量,然后,他并不是使用该变量创建时的值,相反,他使用外部函数函数中该变量最后的值。
2 闭包的用途
1. 匿名自执行函数
有的函数只需要执行一次,其内部变量无需维护,可以使用闭包。
var datamodel={
table:[],
tree:{}
};
(function(dm){
for(var i=0;i<dm.table.rows;i++){
var row=dm.table.row[i];
for(var j=0;j<row.cells;i++){
drawCell(i,j);
}
}
})(datamodel);
创建一个匿名函数,并且立刻执行,外部无法引用它内部的变量,因此在执行完后很快就被释放。不会污染全局对象。
2. 缓存
处理过程中数据缓存,当再次调用的时候,首先从缓存中查找。闭包可以做到这点,因为他不释放外部的引用,函数内部的之可以得以保存。
var CacheSearchBox=(function(){
var cache={};
count=[];
return{
attachSearchBox:function(dsid){
if(dsid in cache){return cache[dsid];}
var fsb = new uinit.webctrl.SearchBox(dsid);//新建
cache[dsid]=fsb;
if(count.length>100){delete cache[count.shift()];}
return fsb;
},
clearSearchBox:function(dsid){
if(dsid in cache){cache[dsid].clearSelection();}
}
}; })();
CachedSearchbox.attachSearchBox("input");
3. 实现封装
在persion之外的地方无法访问其内部的变量,而通过提供闭包形式来访问。
var persion=function(){
//变量作用于为函数内部,外部无法访问
var name="default";
return{
getName : function(){
return name;
},
setName : function(newName){
name=newName;
}
}
}();
print(persion.name);//直接访问,结果为undefined
print(persion.getName());//default
persion.setName("jack");//直接访问,结果为undefined
print(persion.getName());//jack
闭包的另一个重要的用途是实现面向对象中的对象。
function Persion(){
var name="default";
return{
getName : function(){
return name;
},
setName : function(newName){
name=newName;
}
}
};
var john = Persion();
print(john.getName());//defalut
john.setName("john");
print(john.getName());//john