在Javascript中允许函数通过直接量来定义。一般情况下,我们定义函数时,最常见的方式是通过function语句进行定义,例如:
return a+b;
}
这样,sum这个函数就在它所在的作用域中可以被任意调用了。除此之外,函数的定义方式可以通过另外一种方式,就是通过直接量定义。例如上面这个例子,我们可以用另外一种方式:
return a+b;
}
上述代码就是函数通过直接量的方式进行定义。函数直接量是一个表达式,它可以定义匿名函数。函数直接量的语法和function语句十分相似,只不过, 它被用作表达式的一部分,而不是用作语句了。在函数直接量定义中,右侧的function所定义的是匿名函数,并将这个匿名函数的引用传递给表达式左侧。
关于函数直接量定义,需要说明几点:
第一,函数直接量定义方式定义出来的函数是一个匿名函数,尽管通过表达式赋值语句将这个函数赋值给了左侧的变量名,但是,左侧的变量被赋值的是这个匿名函数的引用。
第二,由于函数直接量的定义方式中(代码2),实际上function已经作为一个表达式来看待,因此,表达式左侧的变量就必须在该语句执行之后才会引用 右侧的匿名函数,也就是说,在该语句执行之前,作用域中仅仅是知道有个变量是sum,但是类型未知。于此相反的是,常规的函数语句(代码1)会在 Javascript执行之前进行“预处理”,在它的作用域中,sum一开始就被认知为函数。 一个非常简单的例子:
alert(b);//弹出b.toString()后的结果
var a=function(){return 1;}
function b(){return 1;}
alert(a);//弹出a.toString()后的结果
上 述代码中,第一次alert(a)时,由于“预处理”,该作用域中已经知道存在一个变量a,但是由于还没有执行到第3行,因此,它是undefind,而 b则在一开始时,就已经知道它的类型是函数了。因此,alert(b)时,它会直接执行b.toString()方法尽管它的定义在执行语句的下面。
第三, 虽然函数直接量创建的是匿名函数,但是它的语法也规定它可以指定函数名。只不过这个函数名只在编写调用自身的递归函数时非常有效。为了说明这个问题,先看下面的代码:
alert(sum(5));//120
alert(temp(5));//出错
上 面的代码sum是一个计算n的阶乘(n!)运算,我们可以看到,sum的定义是采用函数直接量方式定义的。但是这里存在一个问题,就是它存在一个函数 名:temp。确切的讲,temp不是函数名,因为为前面已经说了,表达式右侧的function是一个匿名函数,因此,temp不可能是函数名(要不怎 么叫匿名函数呢?)。但是,为什么这样的定义语法没有错误呢?因为Javascript允许指定它的函数名,但是这个函数名不是真正的函数名,它是用来为 它自身递归调用时使用的。(函数体中实际上就是一个递归函数)。我大致把temp理解为匿名函数内部作用域中的函数名,它可以这样调用它自己。因此,在执 行到alert(temp(5))时,浏览器报错了,告诉我们temp是未定义的。
但 是需要指出的是,在Javascript的早期版本中,没有正确的实现这种命名了的函数直接量。在IE678这些版本中,Javascript的版本低于 1.5,因此,它对这种方式的处理没有正确的实现。因此,在执行到alert(temp(5))时,它也是显示和执行sum(5)一样的结果。因 此,temp和sum一样,都被赋值了。这个问题在IE9和更高的版本中,得到了统一修正