闭包是什么?有的朋友会说,闭包就是匿名函数,其实这样的说法是不对的。《javascript高级程序设计》一书中关于闭包我觉得
是说的最好的,就是闭包是指有权访问另外一个函数作用域中的变量的函数。
要理解闭包,首先我们要清楚什么是作用域链。当某个函数被调用时,会创建关于这个函数的作用域链。在作用域链的头部,是
该函数的arguments和其他命名的参数组成的活动对象。而处于第二位的,是距离该函数最近的外部函数的活动对象,然后依次
类推,直到到达全局的活动对象。书上有图,我这里就不画了。
而在创建一个函数的时候,会提前创建一个预先包含外部函数的活动对象的作用域链,并存储在[[scope]]内部属性中,当函数被调用时,
就创建该函数的活动对象并将它加在[[scope]]链条的顶端,从而完成作用域链的创建。当函数执行的时候,查找变量的过程就在作用域
链上进行,从头到尾查找同名的变量,直到找到为止。
从本质上讲,作用域链本质上是一个指向变量对象的指针列表,它仅仅是引用了活动对象(这里很关键,是引用而非保存副本)。
这里列出一个例子:
function createFunction(){
var result = new Array();
for( var i=0;i<5;i++){
result[i] = function(){
return i;
}
}
}
的活动对象,具体来说,该活动对象有两个成员,一个result数组一个i变量。大家不了解闭包的时候乍一看也许觉得这五个函数分别返回0,1,2,3,4;
其实这五个函数返回的值都是5。这是为什么呢?原因就在这五个函数的作用域链是引用的createFunction,在createFunction执行完毕之后,i值变为
了5,所以这五个函数的返回值也都是5了。那大家要问,我们怎么做才能做到我们想要的效果呢?只需要将代码编程如下:
function createFunction(){
var result = new Array();
for( var i=0;i<5;i++){
result[i] = function(num){
return function(){
return num;
}
}(i);
}
}
在这段代码中,我们result数组中的闭包函数的作用域链实际上有三个节点(不包含全局活动对象),分别是自己的空的活动对象,外层匿名函数的活
动对象(包含num),以及createFunction的活动对象。而每个外层匿名函数的活动对象中num值是不一样的,这个是因为我们执行了外层匿名函数从而
在构造作用域链的时候引用了完全不同的num值。(这里可能比较抽象,但是大家想想应该没问题)。
有关闭包的内存泄露这里就不多讲了,大致就是在函数中使用了引用dom对象后需要将对象赋为null以切断作用域链中的循环引用。
闭包的一个高级用处是模仿块级作用域。由于js本身是没有块级作用域的,即下面代码可以执行成功:
function outputNumbers(counts){
for(var i =0;i<counts;i++){
alert(i);
}
alert(i)//counts;
}
块级作用域的标准写法如下:
(function(){
})()
在function中添加var变量,就能做到只有function中的代码可以访问,出了function则无法访问,即实现了块级作用域。例子如下;
var global_obj = null;
(function(){
var private_name = "roger";
global_obj = {
setName:function(name){
private_name = name;
},
getName:function(){
return private_name;
}
};
})();
以上就是我看《javascript高级程序设计》的读后感,后面的内容有机会再看吧,目前就这些了,希望各位看官可以一起交流!