注意最后一个语句:func1.method1.mehotd1(),它调用了method1这个函数对象的method1方法。虽然看上去有点容易混淆,但仔细观察一下语法还是很明确的:这是一个递归的定义。因为method1本身也是一个函数,所以它同样具有函数对象的属性和方法,所有对Function类型的方法扩充都具有这样的递归性质。
Function是所有函数对象的基础,而Object则是所有对象(包括函数对象)的基础。在JavaScript中,任何一个对象都是Object的实例,因此,可以修改Object这个类型来让所有的对象具有一些通用的属性和方法,修改Object类型是通过prototype来完成的:
Object.prototype.getType=function(){ return typeof(this); } var array1=new Array(); function func1(a,b){ return a+b; } alert(array1.getType()); alert(func1.getType()); |
上面的代码为所有的对象添加了getType方法,作用是返回该对象的类型。两条alert语句分别会显示“object”和“function”。
将函数作为参数传递
在前面已经介绍了函数对象本质,每个函数都被表示为一个特殊的对象,可以方便的将其赋值给一个变量,再通过这个变量名进行函数调用。作为一个变量,它可以以参数的形式传递给另一个函数,这在前面介绍JavaScript事件处理机制中已经看到过这样的用法,例如下面的
程序将func1作为参数传递给func2:
function func1(theFunc){ theFunc(); } function func2(){ alert("ok"); } func1(func2); |
在最后一条语句中,func2作为一个对象传递给了func1的形参theFunc,再由func1内部进行theFunc的调用。事实上,将函数作为参数传递,或者是将函数赋值给其他变量是所有事件机制的基础。
例如,如果需要在页面载入时进行一些初始化工作,可以先定义一个init的初始化函数,再通过window.onload=init;语句将其绑定到页面载入完成的事件。这里的init就是一个函数对象,它可以加入window的onload事件列表。
传递给函数的隐含参数:arguments
当进行函数调用时,除了指定的参数外,还创建一个隐含的对象——arguments。arguments是一个类似数组但不是数组的对象,说它类似是因为它具有数组一样的访问性质,可以用arguments[index]这样的语法取值,拥有数组长度属性length。arguments对象存储的是实际传递给函数的参数,而不局限于函数声明所定义的参数列表,例如:
function func(a,b){ alert(a); alert(b); for(var i=0;i<arguments.length;i++){ alert(arguments[i]); } } func(1,2,3); |
代码运行时会依次显示:1,2,1,2,3。因此,在定义函数的时候,即使不指定参数列表,仍然可以通过arguments引用到所获得的参数,这给编程带来了很大的灵活性。arguments对象的另一个属性是callee,它表示对函数对象本身的引用,这有利于实现无名函数的递归或者保证函数的封装性,例如使用递归来计算1到n的自然数之和:
var sum=function(n){ if(1==n)return 1; else return n+sum(n-1); } alert(sum(100)); |
其中函数内部包含了对sum自身的调用,然而对于JavaScript来说,函数名仅仅是一个变量名,在函数内部调用sum即相当于调用一个全局变量,不能很好的体现出是调用自身,所以使用arguments.callee属性会是一个较好的办法:
var sum=function(n){ if(1==n)return 1; else return n+arguments.callee(n-1); } alert(sum(100)); |