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 1;}else{ return 0;} };}</value2){>在这个函数中,由于return的函数它访问了包含函数(外部函数)的变量propertyName,所以我们认为这个函数即为闭包。即使这个闭包被返回了,而且是在其他地方调用了,但是它仍然可以访问propertyName,之所以还能够访问到propertyName这个变量,是因为内部函数(闭包)的作用域链中包含着createComparisonFunction函数的作用域。因此,要彻底搞清楚闭包,就需要彻底搞清楚函数被调用时发生了什么以及作用域链的有关知识。
function compare(value1,value2){ if(value1<value2){return -1; }else if(value1>value2){return 1; }else{return 0; }}<br> var result=compare(5,10);以上代码首先定义了compare()函数,然后又在全局作用域中调用了它。当调用compare函数时,首先创建一个函数执行环境,每个执行环境又对应这一个变量对象,也就是说作用域链和函数执行环境是同时创建的,其中作用域链的前端即为compare函数的活动对象(在函数中,变量对象又称为活动对象)。在compare活动对象中包含了arguments、value1、value2(关键:尽管arguments数组对象包含value1和value2,但是我们还是要分开列举,而不是仅仅认为只有arguments包含于compare的活动对象,因为value1和value2也包含于compare的活动对象)。
作用域链的本质就是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。无论什么时候在函数中访问一个变量,就会从作用域链的前端沿着作用域链搜索具有相应名字的变量。我们知道,全局环境的变量对象始终存在,而局部环境(如compare()函数执行环境)的变量对象只在函数执行的时候存在,一旦执行完毕,局部变量对象(活动对象)就会被销毁。但在闭包中,却与此不同。
把博文开始的代码复制如下:
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 1;}else{ return 0;} };}由于在一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的作用域链中。因此,在createComparisonFunction函数内部定义的匿名函数的作用域中实际包含着外部函数的活动对象。如果我们执行如下代码:
var compare=createComparisonFunction("name");var result=compare({name:"zzw"},{name:"ht"});这时候匿名函数的作用域链将引用着外部函数的活动对象。因为匿名函数从外部函数中被返回后,它的作用域链被初始化为包含外部函数的活动对象和全局变量对象。这样,匿名函数就可以访问外部函数中定义的所有变量。更为重要的是,即使外部函数在执行完毕后,其活动对象也不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象。换句话说,当createComparison()函数返回后,其执行环境的作用域链会被销毁,但是她的活动对象仍然保存在内存中。等到倪敏函数被销毁后,外部函数的活动对象才会被销毁。
(function(){ var now=new Date(); if(now.getMonth()==0&&now.getDate()==1){alert("happy new year"); }})();这就是模仿块级作用域,即定义并立即调用了一个匿名函数。
function outputNumbers(count){ (function(){for (var i=0;i<count;i++){ console.log(i);} })(); console.log(i);}outputNumbers(5);这是在模仿块级作用域之外的console.log(i)就会导致错误,因为i未被定义。说明在执行了模仿块级作用域之后,内部的变量就被销毁了。