闭包是指有权访问另一个函数作用域中的变量的函数,创建的常见方式就是在一个函数内部创建另一个函数。
我们来理解下执行环境和作用域链:
1.执行环境有全局执行环境和函数执行环境之分。
2.每次进入一个新的执行环境,都会创建一个用于搜索变量和函数的作用域链。
3.函数的局部环境不仅有权访问函数作用域中的变量,而且有权访问其包含(父)环境,由底向上乃至全局环境。
4.变量的执行环境有助于确定应该何时释放内存。
执行环境和作用域链
function createComparisonFunction(propertyName){
return function(object1,object2){
var value1=object1[propertyName];
var value2=object2[propertyName];
if(value<value2){
return -1;
}else if(value1>value2){
retutn 1;
}else{
return 0;
}
};
}
//创建函数
var compareNames=createComparisonFunction
("name");
//调用函数
var result=compareNames({name:"joey"},{name:"ross"});
//接触对匿名函数的引用,用于释放内存
compareNames=null;
因为只是用于自己加强理解,就直接把图片放在这里了,因为用于文字实在很难描述出来作用域链的关系。
值得一提的是,每个执行环境都有表示变量的对象--变量对象,全局环境中的变量对象始终存在,而内部函数的局部环境变量则只在函数执行过程中存在。
而在这个例子中,createComparisonFunction()的作用域链包含两个变量对象,一个本身的活动对象,一个全局变量对象,而匿名函数的作用域链包含着三个对象变量,多了一个自身的闭包活动对象,外面访问不进来,里面却可以访问外面,所以也包含外部函数的活动对象和全局变量对象,重要的是,当外部函数执行完毕之后,它的活动对象也不会被销毁,因为匿名函数的作用域链接仍然在引用这个活动对象,换句话说,外部函数返回后,其执行环境会销毁,但是它的活动对象依然留在内存中,知道匿名函数被销毁,外部函数的活动对象才会被销毁。
闭包与变量
function
create(){
var
result=new Array();
for(var
i=0;
i<10,
i++){
result[i]=function(){
return
i ;
}
}
}
//蓝色的全局变量对象,红色的是create()函数活动对象,绿色的闭包的活动对象。
作用域链的这种配置机制引出一个值得注意的副作用,
闭包只能取得包含函数中任何变量的最后一个值。
上面这句话是重点,这个代码我起初没看懂的,反复理解了之后才懂,这个函数会返回一个函数数组,
[0(),1().....9()],从0到9,而函数返回的 i 值应该对应函数名称,即是0()里面返回0,1()里面返回1,以此类推,实际上每个函数返回的都是10,因为 create()这个函数的作用域链保存这这个函数的活动对象,活动对象有result,还有i,函数调用后,变量 i 的值已经是10,并且保存在活动对象里,此时闭包去引用的都是同一个 i 。