跟我学习javascript的arguments对象
1、什么是arguments
arguments是是JavaScript里的一个内置对象,它很古怪,也经常被人所忽视,但实际上是很重要的。所有主要的js函数库都利用了arguments对象。所以agruments对象对于javascript程序员来说是必需熟悉的。在javascript函数体内,标识符arguments具有特殊含义。它是调用对象的一个特殊属性,用来引用Arguments对象。Arugments对象就像数组,注意这里只是像并不是哈。
javascript函数体内,arguments像数组(并不是真的数组,是一个Arguments对象,再次强调)一样,有length属性,可以代表传给函数的参数的个数。
javascript中Arguments对象是函数的实际参数,arguments对象的长度是由实参个数而不是形参个数决定的。形参是函数内部重新开辟内存空间存储的变量,但是其与arguments对象内存空间并不重叠。
js不会主动为你判断你到底给函数传了多少个参数,如果你多传了,多余的部分就没有被使用,如果你少传了,那么没传的参数值就是undefined.所以我们可以借助arguments的length属性来检测调用函数时是否使用了正确数目的实际参数,因为javascript是不会为你做这些事的
functionf(x,y,z)
{
//首先检查传递的参数数量是否正确
if(arguments.length!=3)
{
thrownewError("functionfcalledwith"+arguments.length+"arguments");
}
//下面运行真正的函数
}
2、arguments创建可变参数列表函数
arguments还为我们提供了这样一种可能,就是为一个函数传任意数目的实际参数:
比如说,我想用一个display()函数来计算每个公司的员工工资总额,对,没错,你传多少参数都行,但是前提是你要传数字,因为我在函数内部懒得判断了。
functiondisplay(){
varsum=0;//总额
for(vari=0;i<arguments.length;i++){
sum+=arguments[i];
}
document.write(sum+'<br>');
}
//A公司
display(10000,2000,5000);
//B公司
display(1000,2000,5000,8000,10000);
怎么样?这个方法很巧妙吧?
说明一下arguments与真正传的形式参数是一致的:
对于arguments和值都存在的情况下,两者值是同步的改变其中一个值,即改变了二者所有的值
functionf(a,b,c){
alert(arguments.length);//result:"2"
a=100;
alert(arguments[0]);//result:"100"
arguments[0]="qqyumidi";
alert(a);//result:"qqyumidi"
alert(c);//result:"undefined"
c=2012;
alert(arguments[2]);//result:"undefined"
}
f(1,2);
3、永远不要修改arguments对象
函数中声明的参数和arguments之间的联系很脆弱,每个声明的参数实际上只是对arguments对象中对应位置的一个引用。
值得注意的是,在ES5的strictmode中,函数声明的参数并不会引用arguments:
functionstrict(x){
"usestrict";
arguments[0]="modified";
returnx===arguments[0];
}
functionnonstrict(x){
arguments[0]="modified";
returnx===arguments[0];
}
strict("unmodified");//false
nonstrict("unmodified");//true
正因为在strict和非strict模式下,函数声明的参数和arguments的关系不一致,所以为了避免出现问题,不去修改arguments对象才是最安全的做法。
如果确实需要修改arguments对象,那么可以首先赋值一份arguments对象:
varargs=[].slice.call(arguments);
当slice方法不接受任何参数的时候,就会执行复制操作,得到的args也是一个真正的数组对象。同时,args和函数声明的参数之间也没有任何联系了,对它进行操作是安全的。
4、一个变量来保存arguments的引用
假设需要一个API用来遍历若干元素,像下面这样:
varit=values(1,4,1,4,2,1,3,5,6); it.next();//1 it.next();//4 it.next();//1
相应的实现可以是:
functionvalues(){
vari=0,n=arguments.length;
return{
hasNext:function(){
returni<n;
},
next:function(){
if(i>=n){
thrownewError("endofiteration");
}
returnarguments[i++];//wrongarguments
}
};
}
但是执行的实际情况却是:
varit=values(1,4,1,4,2,1,3,5,6); it.next();//undefined it.next();//undefined it.next();//undefined
原因在于:对于arguments对象的赋值是隐式完成的。在next方法内部,使用了arguments,然而此arguments和values方法开始处的arguments并不是一个对象。这里的arguments对象是函数next()的。
解决方法也很简单,就是将需要访问的arguments使用另外一个变量进行引用。然后通过闭包的性质在其嵌套的函数中进行访问就可以了,像下面这样:
functionvalues(){
vari=0,n=arguments.length,a=arguments;
return{
hasNext:function(){
returni<n;
},
next:function(){
if(i>=n){
thrownewError("endofiteration");
}
returna[i++];
}
};
}
varit=values(1,4,1,4,2,1,3,5,6);
it.next();//1
it.next();//4
it.next();//1
5、arguments对象的callee属性:
arguments的callee属性是用来引用当前正在执行的函数,这对未命名的函数调用自身非常有好处。
首先用命名函数表达式实现递归的函数:
//函数直接量指定函数名递归函数
varresult=functionfact(x){
if(x<=1)
return1;
else
returnx*fact(x-1);
};
那里面,我提到可以为函数直接量以函数名。这样实现递归可以很方便的调用自己。
现在用arguments的这个callee同样可以简单的实现
//用函数直接量,采用arguments.callee属性实现递归函数
varresult=function(x){
if(x<=1)return1;
returnx*arguments.callee(x-1);
};
在最后提醒大家一点,既然这个arguments这么厉害,那么我们就不要为变量命名为arguments了,事实上arguments是javascript的保留字之一。嗯。
最后补充一点:
区别caller
返回一个对函数的引用,该函数调用了当前函数。
- -functionName.caller
- -functionName对象是所执行函数的名称。
对于函数来说,caller属性只有在函数执行时才有定义。如果函数是由顶层调用的,那么caller包含的就是null。如果在字符串上下文中使用caller属性,那么结果和functionName.toString一样,也就是说,显示的是函数的反编译文本。
代码:
CodehighlightingproducedbyActiproCodeHighlighter(freeware)http://www.CodeHighlighter.com/-->//callerdemo{
functioncallerDemo(){
if(callerDemo.caller){
vara=callerDemo.caller.toString();
alert(a);
}else{
alert("thisisatopfunction");
}
}
functionhandleCaller(){
callerDemo();
}
handleCaller();//弹出handleCaller的定义
以上就是针对javascript的arguments对象的相关介绍,希望对大家的学习有所帮助。