函数表达式和闭包

简述:

最近学习了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都是同一个,实现共享。

时间: 2024-08-11 12:08:23

函数表达式和闭包的相关文章

JavaScript基础——函数表达式、闭包

简介 函数表达式是JavaScript中的一个既强大又容易令人困惑的特性.定义函数的方式有两种:一种是函数声明,另一种就是函数表达式.函数声明的语法是这样的: function functionName(arg0 , arg1 , arg2--){ //函数体 } 首先是function关键字,然后是函数的名字,这就是指定函数名的方式.Firefox.Safari.Chrome和Opera都给函数定义了一个非标准的name属性,通过这个属性可以访问到给函数指定的名字.这个属性的值永远等于跟在fu

浅谈JavaScript的函数表达式(闭包)

前文已经简单的介绍了函数的闭包.函数的闭包就是有权访问另一个函数作用域的函数,也就是函数内部又定义了一个函数. 1 var Super=function(num){ 2 var count=num; 3 return function(){ 4 console.log(count); 5 } 6 } 7 var result=Super(3);//此时result是一个函数 8 result();//输出3 上面的代码定义了一个函数Super,同时在Super函数内部又定义了一个匿名函数作为返回

javascript高级程序设计笔记(第7章 函数表达式)

7.5 小结 在JavaScript 编程中,函数表达式是一种非常有用的技术.使用函数表达式可以无须对函数命名,从而实现动态编程.匿名函数,也称为拉姆达函数,是一种使用JavaScript 函数的强大方式.以下总结了函数表达式的特点.? 函数表达式不同于函数声明.函数声明要求有名字,但函数表达式不需要.没有名字的函数表达式也叫做匿名函数.? 在无法确定如何引用函数的情况下,递归函数就会变得比较复杂:? 递归函数应该始终使用arguments.callee 来递归地调用自身,不要使用函数名——函数

Javascript高级程序设计——this、闭包、函数表达式

在javascript中函数声明会被提升,而函数表达式不会被提升.当函数执行时,会创建一个执行环境和相应的作用域链,然后利用arguments和其他的命名参数的值来初始化函数的活动对象,作用域链链中所有的外部活动对象都处于第二的位置. function compare(num1, num2){ if(num1 < num2){ retunr -1; } else if(num1 = num2){ retunr 0; } else(num1 > num2){ retunr 1; } } var

一步步学习javascript基础篇(6):函数表达式之【闭包】

回顾前面介绍过的三种定义函数方式 1. function sum (num1, num2) { return num1 + num2; }  //函数声明语法定义 2. var sum = function(num1, num2){ return num1 + num2; }; //函数表达式定义 3. var sum = new Function("num1", "num2", "return num1 + num2"); //Function

闭包与私有域[第7章-函数表达式 笔记1]

闭包 看如下示例: function createComparisonFunction(propertyName) { return function(object1, object2){ var value1 = object1[propertyName]; var value2 = object2[propertyName]; if (value1 < value2){ return -1; } else if (value1 > value2){ return 1; } else { r

一篇文章带你了解JavaScript中的函数表达式,递归,闭包,变量,this对象,模块作用域

作者 | Jeskson 来源 | 达达前端小酒馆 定义函数的方式: 第一种为 函数声明: 第二种为 函数表达式. 语法: function functionName(arg0, arg1, arg2) { // 函数体 } 在Firefox,Safari,Chrome和Opera有效: 就是通过这个属性可以访问到这个函数指定的名字. console.log(functionName.name); // 'functionName' 函数声明: 它的一个重要特点就是:函数声明提升,就是在执行代码

JS函数表达式 -- 闭包

闭包是指有权访问另一个函数作用域中变量的函数. 创建闭包的常见方式,就是在一个函数内部创建另一个函数.本质上讲,闭包就是讲函数内部和函数外部连接起来的一座桥梁. function a(){ var i = 0; function b(){ alert(++i); } return b; } var c = a(); c(); //1 在函数a 中嵌套了函数b,并将函数b返回. 在执行完 var c = a() 后,变量c实际上指向了函数b,再执行c()后就会弹出一个窗口显示i的值. 当函数a的内

第 13 条:使用立即调用的函数表达式创建局部作用域

第 13 条:使用立即调用的函数表达式创建局部作用域这段程序(Bug 程序)输出什么? function wrapElements(a) { var result = [], i, n; for (i = 0, n = a.length; i < n; i++) { result[i] = function() { return a[i]; }; } return result; } var wrapped = wrapElements([10, 20, 30, 40, 50]); var f