function gn(a,a){
console.info(a);
console.info(arguments[0]);
console.info(arguments[1]);
}
gn(1,2);//2,1,2
gn(1);//undefined,1,undefined
这其实也可以用本文前面关于声明提升的结论来解释:同优先级的后面的覆盖前面的,并且函数参数解析时同时解析值。当然,这样一来,安全性就很成问题了,因此在ES5的严格模式下,重名的形式参数被禁止了。
(3)实际参数的值由形式参数来接受,但如果实际参数和形式参数不一致怎么办呢?答案就是使用arguments来存储,事实上,即便实际参数和形式参数一致,也存在arguments对象,并且保持着和已经接受了实际参数的形式参数之间的同步。将这句话细化一下来理解:
•arguments是一个类数组对象,可以像访问数组元素那样通过方括号和索引来访问arguments元素,如arguments[0]、arugments[1]。
•arguments是一个类数组对象,除了继承自Object的属性和方法(有些方法被重写了)外,还有自己本身的一些属性,如length、callee、caller,这里length表示实际参数的个数(形式参数的个数?那就是函数属性length了),callee表示当前函数对象,而caller只是为了和函数属性caller区分而定义的,其值为undefined。
•arguments是一个类数组对象,但并不是真正的数组对象,不能直接对arguments调用数组对象的方法,如果要调用,可以先使用Array.prototype.slice.call(arguments)先转换为数组对象。
•arguments保存着函数被调用时传入的实际参数,第0个元素保存第一个实际参数,第1个元素保存第二个实际参数,依次类推。
•arguments保存实际参数值,而形式参数也保存实际参数值,这两者之间有一个同步关系,修改一个,另一个也会随之修改。
•arguments和形式参数之间的同步,只有当形式参数实际接收了实际参数时才存在,对于没有接收实际参数的形式参数,不存在这种同步关系。
•arguments对象虽然很强大,但是从性能上来说也存有一定的损耗,所以如果不是必要,就不要使用,建议还是优先使用形式参数。
复制代码 代码如下:
fn(0,-1);
function fn(para1,para2,para3,para4){
console.info(fn.length);//4,形式参数个数
console.info(arguments.length);//2,实际参数个数
console.info(arguments.callee === fn);//true,callee对象指向fn本身
console.info(arguments.caller);//undefined
console.info(arguments.constructor);//Object(),而不是Array()
try{
arguments.sort();//类数组毕竟不是数组,不能直接调用数组方法,抛出异常
}catch(e){
console.info(e);//TypeError
}
var arr = Array.prototype.slice.call(arguments);//先转换为数组
console.info(arr.sort());//[-1,0],已经排好序了
console.info(para1);//0
arguments[0] = 1;
console.info(para1);//1,修改arguments[0],会同步修改形式参数para1
console.info(arguments[1]);//-1
para2 = 2;
console.info(arguments[1]);//2,修改形式参数para2,会同步修改arguments[1]
console.info(para3);//undefined,未传入实际参数的形式参数为undefined
arguments[2] = 3;
console.info(arguments[2]);//3
console.info(para3);//undefined,未接受实际参数的形式参数没有同步关系
console.info(arguments[3]);//undefined,未传入实际参数,值为undefined
para4 = 4;
console.info(para4);//4
console.info(arguments[3]);//undefined,为传入实际参数,不会同步
}
经过测试,arguments和形式参数之间的同步是双向的,但是《JavaScript高级程序设计(第3版)》中第66页说是单向的:修改形式参数不会改变arguments。这可能是原书另一个Bug,也可能是FireFox对规范做了扩展。不过,这也让我们知道,即便经典如此,也还是存有Bug的可能,一切当以实际运行为准。
•结合arguments及其属性callee,可以实现在函数内部调用自身时与函数名解耦,这样即便函数赋给了另一个变量,而函数名(别忘了,也是一个变量)另外被赋值,也能够保证运行正确。典型的例子有求阶乘函数、斐波那契数列等。
复制代码 代码如下: