javascript中的闭包、模仿块级作用域和私有变量
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式为:在一个函数内部创建另一个函数。
“当某个函数被调用时,会创建一个执行环境(execution context)及相应的作用域链。然后,使用arguments和其他命名参数的值来初始化函数的活动对象(activation object).但在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象出于第三位。。。。。直至作用域链终点的全局执行环境。”
function creawteComparisonFunction(propertyName){ return function(object1,object2){ var value1=object1[propertyName]; var value2=object1[propertyName]; if(value1<value2){ return -1; }else if(value1>value2){ return 1; }else{ return 0; } }; }
在匿名函数从createComparisonFunction()中被返回后,它的作用域链被初始化为包含createComparisonFunction()函数的活动对象和全局变量对象。更重要的是,createComparisonFunction()函数在执行完毕后,其活动对象也不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象。或者说,当createComparisonFunction()函数返回后,其执行环境的作用域链会被销毁,但它的活动对象仍然留在内存在,直到匿名函数被销毁后:
//创建函数 var compareNames=creawteComparisonFunction("name"); //调用函数 var result=compareName({name:"gay1"},{name:"gay2"}); //解除对匿名函数的引用(以便释放内存) compareNames=null;
请看如下代码:
function createFunctions(){ var result=new Array(); for(var i=0;i<10;i++){ result[i]=function(){ return i; }; } return result; }
首先得确定:这段代码创建了10个闭包,但结果却不是我们想要的,要达到目的,可以这样:
function createFunctions(){ var result=new Array(); for(var i=0;i<10;i++){ result[i]=function(num){ return function(){ return num; }; }(i); } return result; }
在这个版本中,没有直接把闭包复制给数组,而是定义了一个匿名函数,并将立即执行改匿名函数的结果赋值给数组。这里的匿名函数有一个参数num,也就是最终的函数要返回的值。在调用每个匿名函数时,我们传入了变量i。由于函数参数是按值传递的,所以就会将变量i的当前值复制给参数num。而在这个匿名函数内部,又创建并返回。了一个反问num的闭包。这样一来,result数组中的每个函数都有自己num变量的一个副本,因此就可以返回各自不同的数值了。
“javascript没有块级作用域的概念。” 但是可以使用“私有作用域”的匿名函数语法来打到目的:
function outputNumber(count){ (function(){ for(var i=0;i<count;i++){ alert(i); } })(); alert(i); //报错, 但是如果不实用私有作用域,则正常 }
“私有变量”大家一定比我更了解这个,这里就不谈了。注意一个坑就好:
function Person(name){ this.getName=function(){ return name; }; this.setName=function(value){ name=value; }; } var person1=new Person("gay1"); alert(person1.getName()); var person2=new Person("gay2"); alert(person2.getName()); person1.setName("gay3"); alert(person1.getName()); //gay3 alert(person2.getName()); //gay2 /**************邪恶的分割线***********************/ (function(){ var name=""; Person=function(value){ name=value; }; Person.prototype.getName=function(){ return name; }; Person.prototype.setName=function(value){ name=value; }; })(); var person1=new Person("gay1"); alert(person1.getName()); person1.setName("gay2"); alert(person1.getName()); var person2=new Person("gay3"); alert(person1.getName()); //gay3 alert(person2.getName()); //请注意这里是gay3