zoukankan      html  css  js  c++  java
  • 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和color
    11     }
    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=function(){
     5         return n
     6     }
     7     setvalue=function(x){
     8         n=x;
     9     }
    10 })(); //直接调用
    11 alert(getvalue()); //结果为0
    12 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]()); //结果为1
    16     alert(text[1]());//结果为2
    17     alert(text[2]());//结果为3

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

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

    三、闭包的缺点

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

    四、总结

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

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

      

     

     

     

     

     

  • 相关阅读:
    JS中检测数据类型的方式
    DOM库
    原型应用(将数组去重写到数组的原型上)
    JS学习之原型和原型链模式
    JS学习之闭包、this关键字、预解释、作用域综合
    JS学习之作用域
    JS学习之预解释
    maven gradle 混合使用的问题
    libgdx 开发环境搭建
    maven 安装 jar
  • 原文地址:https://www.cnblogs.com/dirkhe/p/6031426.html
Copyright © 2011-2022 走看看