• 函数表达式和闭包


      简述:

      最近学习了javascript函数表达式和闭包这一块, 记录下自己的学习笔记! 

      学习ECMAscript,函数表达式和'面向对象'这二块是难点,也是重点。

      参考书:<javascript高级程序设计> 工具: EditPlus 浏览器 IE11 ,chrome

      

      1  javascript定义函数的方法主要有二种:

      (1)函数声明

       function p(){//code} 

     (2)函数表达式: 也叫匿名函数

       var p=function(){};

      简单阐述有什么区别?

      

    1 <script type="text/javascript">
    2   <!--
    3      p();
    4      function p(){
    5          alert('函数声明');
    6     }
    7   //-->
    8   </script>

       使用函数声明的方式,上面这样调用没有问题,原因是javascript存在'函数声明提升'。但是var p=function(){} 这样定义就会出错,原因是找不到这个函数(不存在函数声明提升);

     

    2 函数的一些特征:

       (1)Function对象实例  

          函数名是指针,函数是对象;所以函数是没有重载的;

    <script type="text/javascript">
       function a(){alert('a');}
       function a(){alert('123');}
       a(); 
    </script>

     结果:123    很简单:第二个函数和第一函数是不同的对象,a现在指向它,不再指向第一个函数对象,访问的自然也就是第一个函数。

       (2)既然是实例:那么就会有方法和属性---要有这个意识

        比如caller 可以获取调用这个函数的函数的引用;  可以看看下面代码

        

    1         function a(){
    2           b();
    3      }
    4      function b(){
    5         alert(b.caller);
    6      }
    7      a(); // function a(){b();}

        (3)二个重要的内部属性 arguments,this 

       this不用多说,谁调用这个函数就代表谁,注意:函数是一定有调用者的,不可能自行调用。

       arguments 是用来存放函数参数的一个对象,这个对象有个叫callee的属性,代表拥有该arguments的函数,换句话说是正在运行的函数引用

       可以看看下面代码

       

       function c(){
            alert(arguments.callee);
       }
       c();//function c(){//code}

             

       3 函数中定义变量

         定义变量可以这样 var x=1; x=0;区别就在有没有var声明,在window全局中基本没有区别,但是function中是不一样的;一句话来说,var声明

        就是局部变量,不声明那就是window的变量(全局变量);看看下面代码

       

    1 function d(){
    2       name='window name';
    3     }
    4     d();
    5     alert(window.name);//window name

       第2行改为var name='window name' 第5行报错,undefined  

        函数表达式基础的差不多了,接下来重点来了!

      4 作用域链

      理解作用域链是理解闭包的关键;

      (1)什么是执行环境

       执行环境有二种: 全局执行环境;局部执行环境---function里面;

       执行流进入函数执行时,创建执行环境;函数执行结束,回收! 

      (2)变量对象

       理解变量对象非常重要,变量对象在函数中也称为 活动对象,我还是喜欢说成变量对象。

       每一个执行环境都有一个变量对象,变量对象会保存这个执行环境的变量和方法;我们不难想到全局的变量对象是谁? window对象

      我们在全局中添加变量和方法都是添加到window里。函数执行时 执行环境中就会创建变量对象;一般来说:函数调用完毕之后无论是执行环境(出栈),还是变量对象都是回收的。闭包的出现使得变量对象不回收;

      (3)作用域链?

      什么是作用域链:作用域链的本质是 指向变量对象的一组有序指针;字面上很难理解,我第一次看不明白!

      有什么作用:在一个执行环境中对变量和方法进行有序(正确)访问;  

     什么时候创建: 一个函数声明的时候就创建了,作用域链会保存在一个函数的内部属性[[Scope]]中;

      注意:执行流进入函数是: 创建执行环境->将作用域链(利用[[Scope]]属性) 复制到执行环境中->创建变量对象(活动对象)->将变量对象的引用(指针)导入作用域链的最前端->执行代码

      具体请看下面的代码

      

    1         function compare(value1,value2){
    2          if(value1<value2){return 1;}
    3          else if(value1>value2){return -1;}
    4          else{return 0;}
    5       }
    6       var result=compare(5,10)//1

      作用域链图解

      

       我们可以看到,作用域链是什么:有序指针,前面说的作用域最前端在图中就是0位置。 查找变量或者函数是最前端开始的,0指向的活动对象没有你要找的变量,再去1找。0-1其实

       从代码的角度上看其实就是从函数内部一直向函数外部找标识符(变量或者函数),找到立即停止,不会再向上查找。这就是作用域链!

       

      5 闭包

       定义: 闭包是有权访问另外一个函数作用域变量的函数;注意闭包是一个函数!

       创建闭包的主要的方法:在一个函数里面创建一个函数(闭包); 比如

      

    <script type="text/javascript">
        function A(value){
         var num=value;
        return function(){ //闭包
         alert(num);
      }
    }
    var B = A(0);
    alert(B()); //0
    </script>

       在这里匿名函数是一个闭包,一般情况下: 一个函数执行完毕之后,无论是作用域链还是变量对象都会回收,但是这个匿名函数的作用域链里有A()变量对象的引用,所以没有消除。

       还可以访问变量对象的num;这就是闭包的好处!但是闭包的出现加大内存负担,就这里而已,我们即使后面不再使用B函数了,A()变量对象也不会消失,javascript不知道你什么时候还会再用,当然我们可以这样 B=null; 这样的话匿名函数没有引用,被回收,A()变量对象也一起回收!

     《javascript高级程序设计》中尼古拉斯大神建议我们:可以不使用闭包尽量不使用,万不得已才使用!  

       

     6  块级作用域 

      我们都知道javascript是没有块级作用域的,比如{}; if(i=0){}   while(){}  for(){}这些都不会形成块级作用域; 那么怎么创建 java c#类似功能的块级作用域?

      语法:

     (function(){

       //块级作用域

    })();

      注意:  我们创建一个匿名函数,立即调用,里面的代码都要运行一遍,而在window中看不见,这不就是块级作用域吗? 还有一个好处,这个匿名函数没有指针,

     调用后回收,不会产生垃圾(里面的方法,变量都不需要再访问的)。简直就是完美的块级作用域! 注意格式 (匿名函数)其实就是一个指针,再加上()就是调用了。

     

     7 构造函数中的闭包

       (1) 我们知道怎么为对象添加'私有变量' 这样

        

    1    function Person(name,age){
    2     this.name=name;//共有属性
    3     this.age=age;
    4     
    5     var school="一中"; //私有属性
    6     this.GetSchool=function (){return school;}
    7 }

          我们这个school是私有的变量,因为闭包的原因, 对象实例自然可以访问这个变量; 比如  var p=new Person('nos',20); p.GetSchool(); // 一中; 

         (2)现在来一个奇葩: 静态私有属性 ;

          

      (function(){
    
             var school=""; //静态私有;
    
            Person=function(name,age,value){ //构造函数
    
             this.name=name;this.age=age;
    
              school=value;
    
         }; 
    
        Person.prototype.GetSchool=function(){alert(school);}
    
             })();
          var p=new Person('andy',21,'一中');
          p.GetSchool();//一中
          var pp=new Person('nos',29,'二中');
          pp.GetSchool();//二中
          p.GetSchool();//二中

            从结果上看 school是对象共有的,私有的属性, 即静态私有属性; 

           我们看看构造函数是怎么定义的: 没有使用var ,前面说过即使在函数里面定义,没有使用var申明,就是window的,为全局的。自然可以在全局使用! 

          这个匿名函数中调用了一次,只产生一个对象变量,school都是同一个,实现共享。

      

      

  • 相关阅读:
    在ASP.Net中两种利用CSS实现多界面的方法
    c# 添加图片水印,可以指定水印位置+生成缩略图[付上帅图1,2,3,4]
    精力有限,本博客暂停维护,转到www.80back.com(个人的小站)
    设计一个silverlight的Button控件silverlight(银光)学习(1)
    asp.net(c#)上传图片生成缩略图
    DataGrid和存储过程结合的分页,只读取当前页数据
    c#实现google样式的分页
    asp.net MD5加密函数(c#)
    执行JS
    LoadRunner常见问题
  • 原文地址:https://www.cnblogs.com/huang-1995/p/5765878.html
Copyright © 2020-2023  润新知