arguments实参列表
和目前业界流行的各种编程相比(如C,C++,Java,C#),Javascript函数的arguments属性别具一格。它使JavaScript在进行函数调用时更具灵活性。在其他语言中,如果函数形参列表和调用时的实参列表不匹配(参数类型或者参数个数不一致),那么程序就无法编译通过。以C语言代码为例:
void add()
{}
add(1, 2);
以上代码会在代码编译时报错,C++,Java,C#也同样会报错。因为add函数在声明时是无参的,而在实际调用时却向函数传递了两个数值参数。这是很典型的形参列表和实参列表不一致,大多数编程语言都将其视为语法错误。但是在JavaScript中,情况却不是这样,JavaScript解释器不但不将其视为语言错误,而且还能正常地向无参函数传递参数。这一切都是因为有arguments属性的存在。如下面的JavaScript代码:
void add()
{
console.log(arguments[0] + arguments[1]);
}
add(1, 2);
结果为3。因为有arguments,形参列表就显得不重要了,反正最后的计算以实参列表为准。我们在调用时甚至以add(1),add(1,2,3)调用也不会报错,总之,想怎么传就怎么传,只要函数中的计算没有逻辑错误就可以。例如add(1),虽然解释器在语法分析时不会报错,但却会在运行时报错,因为实际计算用到的参数和传递的参数不一样,这是很典型的逻辑错误。我们可以对上述函数进行一些改造,以达到传递任何数量的参数都可以计算总值的目的。代码如下:
void add()
{
let sum = 0;
for(let i = 0; i < arguments.length; i++)
{
sum += arguments[i];
}
console.log(sum);
}
add();//结果:0
add(1);//结果:1
add(1, 2);//结果:3
add(1, 2, 3);//结果:6
arguments的引用特性
arguments是一个类似数组的对象,和数组不一样的是,arguments的length不具有数组的length的特殊行为,数组可以通过设置length改变数组大小,而arguments不能改变自身大小。更为特殊的是arguments的引用特性。何为arguments的引用特性《JavaScript权威指南》上这样解释:Arguments对象和参数名为引用同一个值提供了两种途径。用参数名改变参数的值,会同时改变Arguments对象获取的值,反之,用Arguments改变参数的值也会改变参数名的值。不妨以代码为例:
function Fun(x, y)
{
var arr = new Array();
arr[0] = y;
arr[0] = 4;
arguments[0] = 4;
console.log(x, y);//打印 4,2
}
Fun(1,2);
在上述代码中,arr是一个数组,arguments是类数组对象。arr[0]引用了y,arguments[0]引用了x,我们对引用的值进行修改,结果是x的值被修改了,而y的值没有修改。实际上, arr[0] = y并没有传递y值本身,而是传递了y的一个副本,因此在运行时, arr[0] 和y实际上是两个数值,因此改变 arr[0] 不会影响y。而arguments[0]和x却是指向同一个值,两个中任何一个改变另外一个也会跟着改变。这就是arguments的引用特性。它使得值类型的参数具有引用类型的特征。这一点很重要,却容易被人忽略。
形参和实参的严格匹配
尽管在JavaScript中参数传递更加随意灵活,但有时候我们也需要添加一定的限制,比如我们效仿其他语言的做法,让形参列表和实参列表必须完全匹配,否则返回错误。在这里我们需要用到callee对象,它表示函数自身,callee对象的length属性表示函数形参列表的个数。因此我们可以用它和arguments.length比较。如果一样,则表示形参列表和实参列表一致,允许调用,如果不一样,则表示形参列表和实参列表不一致,抛出错误。因为JavaScript是弱类型语言,形参并不规定类型,因此这里的严格匹配只是做参数个数匹配,不匹配类型。代码如下:
function check(args)
{
var actual = args.length;//实参个数
var exped = args.callee.length;//形参个数
if(actual != expected)
{
throw new Error("参数列表不匹配,期望值:" + exped + " 实际值:" + actual);
}
}
function fun(x, y, z)
{
check(arguments);//实际计算前先检查形参和实参是否匹配
return x + y + z;
}
fun(1);//报错
fun(1, 2);//报错
fun(1, 2, 3);//打印 6
fun(1, 2, 3, 4);//报错
好了,关于arguments的内容就是这些,你是否都掌握了呢?
网友评论