函数声明语句:function f(x){},其中x就是参数。
参数分为两种:
- 形参(parameter):函数定义时圆括号里的数据。
- 实参(arguments);函数调用时,传给函数作为参数的数据。
EMCAScript规定在调用函数时,可传入任意数量,任意类型的参数,可以不跟函数定义时传入的形参数量相对应。为什么会这样呢?
原因就是,EMACAScript中的参数在内部是用一个数组来表示的,函数接收的始终是这个数组,而不关心包含哪些参数。而且,在函数体内也可以通过arguments这个对象来访问这个参数数组,从而获取传递给函数的每一个参数。(arguments就是一个对象--函数的一个内部对象,和this一样。)因此arguments看起来就像一个类数组了。可以用arguments[n]来访问各个位置的元素了.
要了解arguments对象,就需要先函数的内部属性。
函数内部,有两个特殊对象:arguments 和 this。
arguments是一个类数组对象,包含着传入函数中的所有参数。该对象有一个属性callee,该属性是一个指针,指向拥有这个arguments对象的函数。经典例子是阶乘函数:
1 function factorial(num){ 2 if(num <= 1){ 3 return 1; 4 }else{ 5 return num * factorial(num-1); 6 } 7 } 8 9 //修改一下,消除函数的执行与函数名紧密的耦合在一起, 10 function factorial(num){ 11 if(num <= 1){ 12 return 1; 13 }else { 14 return num * arguments.callee(num-1); 15 } 16 } 17 18 //修改后函数名factorial就没出现在函数体内部,因此,无论引用函数时使用什么名字,都能保证正常完成递归。 19 //例如 20 var trueFactorial = factorial; 21 factorial = function(){ 22 return 0; 23 }; 24 alert(trueFactorial(5)); //120 25 alert(factorial(5)); //0 26 //在上面的例子里,变量trueFactorial 获得了factorial的值,实际上就是在另一个位置上保存了一个指向函数的指针,就是让另一个变量也可以应用该函数,正如在函数定义时说的,函数名是一个指向函数的指针,函数体本身存在那里,通过函数名可以访问罢了,二者相互独立,又存在某种联系。 27 //然后将一个返回0的新函数赋给变量factorial。如果在函数体内有变量名factorial,如第一个例子,则trueFactorial()就会返回0.但改成arguments.callee后就能够让trueFactorial正常计算。
与callee属性对应的就是caller属性,arguments对象也拥有caller属性,即:arguments.caller。但在严格模式下访问它会报错,而在非严格模式下这个属性始终是undefined。该属性主要就是为了分清arguments.caller和函数的caller属性。函数的caller属性指向调用该函数的外部函数。
arguments.callee.caller 和函数的caller属性等效。
function outer(){ inner(); } function inner(){ alert(inner.caller); //等价于alert(arguments.callee.caller); } outer(); //返回outer函数的代码
arguments还有一个length属性,返回传入参数的个数。和Array.length类似。
前面说的在函数内部可以通过arguments对象访问传入的参数。那也可以和命名参数一起在函数内部使用:
function doAdd(num1,num2){ if(arguments.length == 1){ alert(num1 + 10); }else if(arguments.length == 2){ alert(arguemnts[0] + num2); } }
还有一点。arguments的值永远与对应的命名参数保持同步:
function doAdd(num1,num2){ arguments[1] = 10; alert(arguments[0] + num2); }
什么意思呢?就是每次执行这个函数时,里面的arguments[1]都会被设成10,对应的num2也会跟着变着10。
最后一点:没有传递值的命名参数将自动被赋予undefined,就像变量没有初始化一样。
关于函数定义时的参数,其实就像在函数内部定义的变量一样,只不过不用在显性的使用var来进行定义。