第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(value1<value2){
return -1;
}else if(value1>value2){
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仍然有效,递归调用依然能正确完成。
所以,使用命名函数表达式来编写递归函数的时候,无论是在严格模式下还是非严格模式下都能行得通。