2018-11-30

第7章 函数表达式

定义函数的方式有两种:

1、函数声明

函数声明的语法:

function functionName(arg0,arg1,arg2){
    //函数体
}

关于函数声明,它的一个重要特征就是函数声明提升。意思是在执行代码之前会先读取函数声明。这就意味着可以把函数声明放在调用它的语句后面。

sayHi();
function sayHi(){
    alert("HI");
}//HI  
//这个例子不会跑出错误,因为在代码执行之前会先读取函数声明
2、函数表达式

函数表达式有几种不同的语法形式,下面是最常见的一种:

var functionName=function(arg0,arg1,arg2){
    //函数体
}
//创建一个函数并将它复制给变量functionName、
//这种情况下创建的函数叫做匿名函数
//因为function关键字后面没有标识符

函数表达式与其他表达式一样,在使用前必须先赋值,不然会导致错误。

sayHi();//这是错误的写法:函数还不存在
var sayHI=function(){
    alert("Hi");
};

能够创建函数再赋值给变量,也就能够把函数作为其他函数的值返回。

function createComparisonFunction(propertyName){
      return function(object1,object2){
          var value1=object1[propertyName];
          var value2=object2[propertyName];
          if(value1value2){
                return 1;
           }else{
                return 0;
           }
      };
}

//这里的createComparisonFunction()就返回了一个匿名函数

返回的函数可能会被赋值给一个变量,或者以其他方式被调用;不过在createComparisonFunction()函数内部,它是匿名的。
在把函数当成值来使用的情况下,都可以使用匿名函数。不过这并不是匿名函数唯一的用途。

7.1递归

递归函数是在一个函数通过名字调用自身的情况下构成的:

function factorial(num){
    if(num<=1){
      return 1;
    }else{
        return num*factorial(num-1);
    }
}
//这是一个经典的递归阶乘函数。虽然这个函数表面看来没什么问题,但下面的代码却可能导致它出错。

var anotherFactorial = factorial;
factorial = null;
alert(anotherFactorial (4));//出错

//由于将factorial 设置为 null,结果指向原始函数的引用只剩下一个。
//当调用anotherFactorial ()时,由于必须执行factorial ,这个时候factorial 已经不再是函数,所以就导致错误

这种情况下,使用arguments.callee可以解决这个问题
arguments.callee是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用:

function factorial(num){
    if (num<=1){
        return 1;
    }else{
        return num*arguments.callee(num-1)
    }
}

通过使用arguments.callee代替函数名,可以确保无论怎样调用函数都不会出问题。

但是如果在严格模式下,不能通过脚本访问arguments.callee,会导致错误。
不过可以使用命名函数表达式来达成相同的结果:

var factorial = (function f(num){
    if(num <=1){
        return 1;
    }else{
        return num*f(num-1);
     }
});
//创建一个名为f()的命名函数表达式,将它赋值给变量factorial 。
//即便把函数赋值给了另一个变量,函数的名字f仍然有效,递归调用依然能正确完成。

所以,使用命名函数表达式来编写递归函数的时候,无论是在严格模式下还是非严格模式下都能行得通。

你可能感兴趣的:(2018-11-30)