深度理解javascript 闭包

来源:互联网 发布:非凡软件(霏凡软件) 编辑:程序博客网 时间:2024/04/26 12:10

闭包是javascript的一个难点,很难理解。但也是其显著的特性之一。掌握之后,可以实现很多很飘逸的功能。

理解闭包有2个关键点

1.作用域链

2.函数作为一个变量


1.作用域链

在javascript中,不像强类型语言是块级作用域,也就是局部变量只在一个花括号内部有效,而是函数作用域,局部变量在整个函数里面有效并且在内部嵌套的函数里面也有效。每执行一个函数就会创建一个作用域对象,嵌套的函数,作用域对象就会以链表的形式连接。当访问一个属性的时候,会现在当前作用域寻找,没有就往上级的作用域中寻找,都没有就返回undefined。

       var a = 'aaa';       var fun =  function (){            alert(a);            var a = 'ccc';            alert(a);        }
这个例子,按理说fun是window对象的内部函数,应该可以访问window对象的属性的,但是alert() 为undefined,原因是javascript的解释器将var提前了。

换句话说,当执行fun的时候,开辟了新的执行作用域,这时声明提前,由于a与外部变量重名,外部a会被隐藏,内部访问的都是里面的a,所以alert的时候,还没有执行到赋值语句,所以是undefined。从这里也可以看出,在函数内,只要声明了变量,那么在整个函数内都可用,而与在哪里定义无关。


2.函数变量

在javascript中我们可以直接返回一个函数,也可以直接把函数赋值给一个变量。所以我们常会看到这种写法

     function f1(){         var aa = 99;         function f2(){             aa++;         }         return f2();     }       var fff = f1();       fff();

函数f1直接返回了f2,其实f2就是一个闭包了。我们可以稍微狭义一点理解,闭包就是一个引用了外部函数变量的函数。f2是可以操作f1的变量的,现在又把f2的引用赋值给了fff,所以当f1执行完毕之后,其作用域不会消失,因为还有其他函数引用他内部的变量。这就实现了,保存执行环境的功能。这在很多时候是非常有用的。


3.闭包

现在我们可以正式来说闭包了。

闭包有2个主要的功能

1.给予外部访问函数内部的能力

2.保存变量或者执行环境不会被回收

for(var i =0; i<link.length; i++){     link[i].onclick = function(){ alert(i); }; }

这是一个非常经典的例子,执行结果,i一直是最后一个。原因是当调用点击事件的时候,for循环已经执行完毕了。所以i一直是最后一个。有2中解决办法

方案1、闭包

for(var i =0; i<link.length; i++){ link[i].onclick = (function(i){return function(){  alert(i);};})(i);}

我们的目的就是保存每次执行到onclick定义时的i值。所以用了()()小括号,返回函数表达式的值,让函数在定义后立即执行,这个时候会新建一个作用域,而我们在内层又创建了一个函数,让它引用该作用域的变量,从而形成闭包,使得它不会被回收。这样我们就保存了每个i值在不同的作用域中。很明显,闭包会占用更多的资源, 而且要注意对象间的循环引用,否则会造成内存溢出。


方案2、属性

我们的目的就是保存每次执行到onclick定义时的i值,那么把i保存为当前对象的一个属性就ok,link[i].index = i;  然后在onclick函数里面直接调用属性,this.index即可。这种方式简单,而且方便。



0 0
原创粉丝点击