一个函数,有名字,有参数,有返回值。函数是代码重用的最常见方式。
先看一段代码:
function max(a,b){ // Method (1) : function statement return Math.max(a,b); } alert(typeof(window.max)); // == function var max = function(a,b){ // Method (2) : function expression return Math.max(a,b); }; alert(typeof(window.max)); // == function alert(max(3,4)); // works well max = function my_max(a,b){ // Method (3) return Math.max(a,b); }; alert(typeof(window.max)); // == function alert(max(3,4)); // works well alert(typeof(my_max)); // == undefined
第一种函数声明方法是最基本的方法。并且我们注意到函数名'max'成了全局对象window的一个属性。事实上,第一种声明方法和第二种方法是等效的。第三种声明方法跟第二个相比,只多了一个函数名'my_max',并且我们注意到'my_max'在的代码中却是 undefined。因此,对于JavaScript中的函数有以下一些事实:
JavaScript的函数支持可变长度参数。函数定义时的参数列表本质上不过是给参数提供了一个别名。
function max(a){ return Math.max(a, arguments[1]); } alert(max()); // = NaN alert(max(1)); // = NaN alert(max(2,3)); // = 3 alert(max(4,5,6)); // = 5
上面代码中函数'max'定义时参数列表中只有一个参数'a',但在调用时却可以接受任意个参数。事实上,JavaScript中函数的参数只跟叫做 arguments
的对象实例有关。
arguments
可以看作一个数组,这个数组包含了传递给函数的所有参数。但它实际上不是一个数组(Array)。比如,它并没有 pop
这个方法。arguments
除了 length
属性用来标识参数的数目,还有一个 callee
属性用来指向当前正在执行的函数。
callee
有什么用呢?也许唯一的用法就是实现一个匿名的递归调用函数。下面是 MDC 上的例子:
function makeFactorialFunc() { alert('making a factorial function!'); return function(x) { if (x <= 1) return 1; return x * arguments.callee(x - 1); }; } var result = makeFactorialFunc()(5); // returns 120 (5 * 4 * 3 * 2 * 1)
上面有提到,每个function都其实是一个Function Object的实例。因此,我们也可以通过Function对象来创建一个函数。比如:
var max = new Function('a', 'b', 'return Math.max(a,b);');
这和上面利用 'function'语句来定义函数达到的效果是一样的。但却给动态定义函数提供了可能。
如果函数是通过function
statement的方式来定义的话,是可以在函数定义之前调用该函数的。下面的例子同样来自 MDC,是可以运行的。
foo(); // works well function foo() {alert('FOO!'); }
Function 对象有两个特别的方法,call
和apply
。这两个方法可以给函数传递一个对象作为this
指针。两者的不同只是在于函数参数传递方法的不同。
function print(a,b){ alert(this.name +', ' + a + b)} print.apply({name:'Sean'},[1,2]); // OK print.call({name:'Sean'},3,4); // OK print.apply({name:'Sean'},5,6); // 错误。apply 要求传递的参数以数组形式出现