首页 > 代码库 > js学习笔记之作用域链和闭包

js学习笔记之作用域链和闭包

 在学习闭包之前我们很有必要先了解什么是作用域链

一、作用域链

作用域链是保证对执行环境有权访问的所有变量和函数的有序访问。

这句话其实还是蛮抽象的,但是通过下面一个例子,我们就能清楚的了解到作用域链了。

 1 var color="blue"; 2     function changeColor(){ 3         var anotherColor="red"; 4         function swapColors(){ 5             var tempColor=anotherColor; 6             anotherColor=color; 7             color=tempColor; 8             //这里面可以访问color、anotherColor和tempColor 9         }10         //这里面可以访问anotherColor和color11     }12     //这里面只能访问color

以上代码涉及了3个执行环境:全局环境、changeColor()局部环境和swapColor()局部环境。在一个变量环境中只能访问他自己的环境和父执行环境。swapColor()的父执行环境就是changeColor(),而changeColor()的父执行环境就是全局环境。如果还不清楚可以参考下图

     技术分享 

在f2()函数的局部环境中能访问自己和比它等级高的,也就是a,b,c,同理f1()函数环境访问b,a,全局环境只能访问c。

我们这时候会发现函数外部是无法访问内部的局部环境的,但是我们想突破作用域链怎么办呢?这时候就有了闭包共享作用域。闭包这个名词就出现了。

二、闭包

闭包在红宝书中的解释就是:有权访问另一个函数作用域中的变量的函数。

下来举一个简单的例子

1  function f1(){2         var a=1;3         return function(){4             return a;5         }6     }7     alert(a);  /*结果为 a is undefined*/8     var task=f1(); /*task就是闭包,有权访问其他函数作用域变量*/9     alert(task());/*结果为1*/

下来我们再举一个闭包的例子

 1 function f1(){   2       var n=0; 3       task=function(){  //匿名函数 4           n+=1; 5       } 6       //这部分为闭包 7       function f2(){     8           alert(n); 9       }10       return f2 //返回       12   }13     var text=f1(); 14     alert(text()); 15     task();16     alert(text()); //结果依次为 0,undefined,1,undefined

text是f2闭包函数,实际上f2()被赋予一个全局变量,f2()始终在内存中,f1()是它的父级函数,所以f1()也始终在内存中,不会被销毁。执行一次task()后,值变为2。至于为什么会出现undefined是因为,undefined是text的返回值,也就是闭包函数无返回值了。

有时候我们想改变其他函数作用域里的变量,这时候就可以用闭包去解决。设置两个额外的函数去访问内部函数。

 1 var setvalue,getvalue; 2 (function(){ 3     var n=0; 4     getvalue=http://www.mamicode.com/function(){ 5         return n 6     } 7     setvalue=http://www.mamicode.com/function(x){ 8         n=x; 9     }10 })(); //直接调用11 alert(getvalue()); //结果为012 setvalue(456);13 alert(getvalue());/*结果为456*/

这时候我们发现在外部就可以去改变内部变量值。

下来再举一个利用闭包循环遍历得到数组的值。有两个程序,可以对比一下两个程序的区别

例1:

 1 function f1(){ 2     var a=[]; 3     var i=0; 4     for(i=0;i<3;i++){ 5         a[i]=function(){ 6             return i; 7         } 8     } 9     return a;10 }11   var text=f1();12     alert(text[0]()); 13     alert(text[1]());14     alert(text[2]()); //结果都为3

因为闭包都指向局部变量i,只是给出了指针链接,对变量的引用,并没有对值作出改变。所以结果都为3

例2:

 1  function f1(){ 2        function f2(x){  //闭包 3            return function(){ 4                return x; 5            } 6        } 7        var a=[]; 8        var i=0; 9        for(i=0;i<3;i++){10            a[i]=f2(i);11        }12        return a;13    }14     var text=f1();15     alert(text[0]()); //结果为116     alert(text[1]());//结果为217     alert(text[2]());//结果为3

利用一个函数参数,用闭包去获取内部变量的值。

程序是这样走的:先判断谁进来--》调用闭包--》闭包返回内部函数参数--》最后再创建数组。

三、闭包的缺点

  这上面几个例子确实体会到了闭包的强大,但是闭包也有明显的缺点,它使函数中的变量都保存在内存中,占用内存,导致页面加载缓慢。所以再退出函数前,将不用的局部变量删除。

四、总结

  以上就是我学习闭包总结的一点小知识。大家互相交流哈 O(∩_∩)O。

  附阮一峰老师对闭包的理解:http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html?20120612141317#comments 

  

 

 

 

 

 

 

js学习笔记之作用域链和闭包