【JavaScript】之函数表达式

今天主要复习了《JavaScript高级程序》中 函数表达式 这一章,主要是自己对闭包和this的概念还是理不清楚,导致在做小demo的时候这一块完成时懵懂不知的,先做个知识梳理,再继续加强实践吧..

一、函数表达式的特征

函数声明,在执行代码之前会先读取函数声明(同时意味着可以将函数声明放在调用它的语句的后面)

function functionName (arg0,arg1,arg2){

             //函数体

}

使用函数表达式定义函数时,无需对函数命名,从而也可以创建匿名函数。

函数表达式的特点:

  • 函数表达式不同于函数声明。函数声明要求一定要有名字,函数表达式不需要,没有名字的函数表达式也叫匿名函数。
  • 使用函数实现递归,递归函数应该始终使用argument.callee来递归地调用自身,不要使用函数名——函数名可能会发生变化。
function factorial(num){
   if(num<=1){
      return 1;
}else{
     return num*arguments.callee(num-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{
                       return 0;
            }
}
//内部函数访问了外部函数中的变量propertyName
   

如何彻底地理解闭包?

知道有关如何创建作用域以及作用域链有什么作用的细节。

变量对象:后台的每个执行环境都有一个表示变量的对象。

全局环境的变量对象始终存在,而像compare()函数这样的局部环境的对象变量,则只在函数执行的过程中存在。

function compare(value1,value2){   //①定义了compare函数
    if(value1<value2){
        return -1;
}else if(value1>value2){
        return 1;
}else{
       return 0;
    }
}
var result = compare(5,10);  //②全局作用域中调用compare(),这时,会创建一个包含arguments、value1、value2的活动对象

全局执行环境的变量对象(result、compare)在compare()执行环境的作用域链中处于第二位。

一般来讲,当函数执行完毕后,局部活动对象就会被销毁,内存中仅存全局作用域(全局变量对象)。

    1. 在后台执行环境中,闭包的作用域链包含着它自己的作用域、包含函数的作用域、全局作用域。
    2. 通常,函数的作用域及其所有变量都会在函数执行后被销毁。
    3. 但是,当函数返回了一个闭包时,这个函数的作用域将会一直在内存中保存到闭包不存在为止。

关于this对象

this对象是运行时基于函数的执行环境绑定的,在全局函数中,this等于window,而当函数被作为某个对象调用时,this等于那个对象

(每个函数在被调用时都会自动的取得两个特殊变量,this和arguments,内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远比可能直接访问外部函数中的这两个变量。)

不过,把外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象了。

var name = "The Window";

var object = {
        name: "My Object",

       getNameFunc: function(){

              var that = this;

              return function(){
                       return that.name;
            };
      }
};
alert(object.getNameFunc()());   //"My Object"  

当闭包的作用域保存着无法被销毁的元素时,其内存永远不会被回收,这就导致了内存泄漏。所以我们使用闭包模仿块级作用域来解决问题。

三、模仿块级作用域

  1. 创建并立即调用一个函数,这样既可以执行其中的代码,又不会在内存中存下对该函数的引用。
  2. 结果就是函数内部的所有变量都会被理解销毁,不会造成内存泄漏或变量污染全局作用域
function outputNumbers(count){
   (function(){
           for(var i =0;i<count;i++){
               alert(i);   //匿名函数是一个闭包,它能够访问包含作用域中的所有变量
      })();
      alert(i);
}

四、私有变量

任何函数中定义的变量,都可以认为是私有变量,因为不能在函数的外部访问这些变量。

私有变量包括函数的参数,局部变量和在函数内部定义的其他函数。

  • 我们可以使用闭包来实现能够有权访问私有变量的共有方法,该方法也叫特权方法
  • 而实现特权方法,我们使用构造函数模式、原型模式来实现,也可以使用模块模式、增强的模块模式来实现实例的特权方法。

原型模式

(function MyObject(){

      //私有变量和私有函数
      var privateVariable = 10;

      function privateFunction(){
            return false;
}
      //构造函数

MyObject = function(){  //函数声明只能创建局部函数,所以使用函数表达式     };   
      //公有/特权方法
      MyObject.property.publicMethod = function(){   

privateVariable ++; return privateFcuntion();       }; })();

这个模式中,私有变量和函数都由实例共享,由于特权方法是在原型上定义的,因为所有实例都使用同一个函数。

而特权方法,作为一个闭包,总是保存着对包含作用域的引用。

(function(){

      var name= "";

      Person = function(value){
             name = value;
     };

    Person.prototype.getName = function(){
           return name;
   }
   Person.prototype.setName = function(value){
         name = value;
};

})();

var person1 = new Person("Nicholas");
alert(person1.getName());  //"Nicholas"
person1.setName("Greg");
alert(person1.getName());  //"Greg"

var person2 = new Person("Michael");
alert(person1.getName()); //"Michael"
alert(person2.getName());//"Michael"

以这种方式创建静态私有变量会因为使用原型而增进代码的复用,但每个实例都没有自己的私有变量。

模块模式

为单例创建私有变量和特权方法,单例,指的就是只有一个实例的对象。

//在web应用程序中,我们经常需要使用一个实例来管理应用程序级的信息,这个简单的例子创建了一个用于管理组件的application对象。

var application = function(){
        //私有变量和函数
       var components = new Array();            //先声明了一个私有的components数组
       //初始化
       compenents.push(new BaseCompenent());    //并向该数组中添加了一个BaseComponent的新实例

      //公共
       return {       //返回对象的getComponentCount()和registerComponent()方法,它们都是有权访问数组component的特权方法

        getCompenentCount : function(){
                     return compenents.length;
        },
        registerComponent : function(component){
                 if(typeof component =="object"){
                   components.push(component);
             }
         }
        };
}();

简而言之,如果必须创建一个对象并以某些数据对其进行初始化,同时还要公开以一些能够访问这些私有数据的方法,那么就可以使用模块模式。

时间: 2024-12-18 04:14:51

【JavaScript】之函数表达式的相关文章

谈谈javascript的函数表达式及其应用

我们都知道定义函数的方式有两种,一种是函数声明,另外一种就是函数表达式. 函数声明 语法为:function关键字后跟函数名.例如: function functionName(arg0) { //函数体 } alert(functionName.name) // "functionName" 函数声明最主要的特征就是函数声明的提升,所以我们可以把函数声明放在调用它的语句的后面,因为执行代码前会先读取函数声明.比如: hello(); function hello(){ alert(&

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中函数表达式的问题讨论

#函数表达式 ##函数声明和函数表达式的区别 函数的定义有两种形式,一种是函数声明,一种是函数表达式 使用声明时,要注意函数声明提升现象,比如说在if语句中使用声明会出错,但是表达式就不存在这个问题 表达式要在使用前定义,而声明不用 通过声明会获得一个name属性,而表达式中其name为空 function fn() {}     var fn1 = function() {};     console.log(fn.name);    //fn     console.log(fn1.name

JavaScript高级 函数表达式 《JavaScript高级程序设计(第三版)》

函数表达式的特征 使用函数实现递归 使用闭包定义私有变量 前面我们说到定义函数有两种方式:函数声明.函数表达式. 两者的区别在于函数声明提升,前者在执行之前的上下文环境中直接被赋值,而后者不会. 一.递归 递归函数是一个函数通过名字调用自身的情况下构成的. function factorial(num){ if(num<1){ return 1; }else{ return num * arguments.callee(num-1); } } alert(factorial(10)); 二.闭包

浅谈JavaScript的函数表达式(递归)

递归函数,在前面的博客中已经简单的介绍了.递归函数是一个通过函数名称在函数内部调用自身的函数.如下: 1 function fac(num){ 2 if(num<1){ 3 return 1; 4 } 5 else{ 6 return num*fac(num-1); 7 } 8 } 上面的代码,在第一行声明了一个fac函数,同时在6行调用了fac函数本身.这是一个求阶乘的递归函数. 1 var anthorfacc=fac; 2 fac=null; 3 anthorfacc(4);//抛出异常

javascript 函数声明和函数表达式的区别(学习笔记)

javascript中声明函数的方法有两种:函数声明式和函数表达式. 区别如下: 1).以函数声明的方法定义的函数,函数名是必须的,而函数表达式的函数名是可选的. 2).以函数声明的方法定义的函数,函数可以在函数声明之前调用,而函数表达式的函数只能在声明之后调用. 3).以函数声明的方法定义的函数并不是真正的声明,它们仅仅可以出现在全局中,或者嵌套在其他的函数中,但是它们不能出现在循环,条件或者try/catch/finally中,而 函数表达式可以在任何地方声明. 下面分别用两种方法定义函数:

JavaScript中的函数表达式

在JavaScript中,函数是个非常重要的对象,函数通常有三种表现形式:函数声明,函数表达式和函数构造器创建的函数. 本文中主要看看函数表达式及其相关的知识点. 函数表达式 首先,看看函数表达式的表现形式,函数表达式(Function Expression, FE)有下面四个特点: 在代码中须出现在表达式的位置 有可选的函数名称 不会影响变量对象(VO) 在代码执行阶段创建 下面就通过一些例子来看看函数表达式的这四个特点. FE特点分析 例子一:在下面代码中,"add"是一个函数对象

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高级程序设计笔记(第7章 函数表达式)

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