arguments[]
arguments[]数组只定义在函数体中,在函数体中,arguments指代该函数的Arguments对象,该对象拥有数值属性,可当作数组来用,含有传入到该函数的所有参数。arguments标识符本质上是一个局部变量,在每个函数中会自动声明并初始化该变量。arguments仅在函数体中时才指代Arguments对象,在全局代码中为undefined。
可变长的实参列表;实参 对象
问题:
当调用函数的时候传入的实参个数超过函数定义时的形参个数时,没有办法直接获得未命名值的引用。
解决:
参数对象解决了这个问题。在函数体内,标识符arguments是指向实参对象的引用,实参对象是一个类数组对象,这样可以通过数字下标就能访问传入函数的实参值,而不用非要通过明治来得到实参。
例如
假设定义了函数 f ,它的实参只有一个 x 。如果调用这个函数时传入两个实参,第一个实参可以通过参数名 x 来获得到,也可以通过 arguments[0] 来得到。第二个实参只能通过 arguments[1] 来得到。此外,和真正的数组一样, arguments 也包含一个 length 属性,用以标识其所包含元素的个数。因此,如果调用函数 f() 时传入两个参数, arguments.length 的值就是2。
上代码
实参对象在很多地方都非常有用,下面的例子展示了使用它来验证实参个数,从而调用正确的逻辑,因为 JavaScript 本身不会这么做。
function f(x,y,z)
{
//首先,验证传入实参的个数是否正确
if (arguments.length != 3) {
throw new Error("function f called with" + arguments.length + "arguments,but it expects 3 arguments.");
}
//再执行函数的其他逻辑...
}
需要注意的是,通常不必像这样检查实参个数。大多数情况下 JavaScript 的默认行为是可以满足需要的;省略的实参都将是 undefined ,多出的参数会自动省略。
实参对象有一个重要的用处,就是让函数可以操作任意数量的实参。下面的函数就可以接收任意的实参,并返回传入实参的最大值(内置函数Max.max()的功能与之类似);
function max() {
var max = Number.NEGATIVE_INFINITY;
//遍历实参,查找并记住最大值
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] > max) max = arguments[i];
//返回最大值
}
retrun max;
}
var largest = max(1, 10, 100, 2, 3, 1000, 4, 5, 10000, 6); // => 10000
类似这种函数可以接收任意个数的实参,这种函数也称为“不定实参数”(varargs function)这个术语源自古老的C语言。
注意,不定实参函数的实参个数不能为零,arguments[] 对象最适合的应用场景是在这样一类函数中,这类函数包含固定个数的命令和必须参数,以及随后个数不定的可选实参。
记住,arguments并不是真正的数组,它是一个实参对象。每个实参对象都包含以数字为索引的一组元素以及 length 属性,但它并不是真正的数组。可以这样理解,它是一个对象,只是碰巧具有数字为索引的属性。
数组对象包含一个非同寻常的特性。在非严格模式下,当一个函数包含若干形参,实参对象的数组元素是函数形参所对应实参的别名,实参对象中以数字索引,并且形参名称可以认为是相同变量的不同命名。通过实参名字来修改实参值的话,通过 arguments[] 数组也可以获取到更改后的值,下面这个例子清楚地说明了这一点;
function f(x) {
console.log(x); //输出实参的初始值
arguments[0] = null; //修改实参数组的元素同样会修改x的值
console.log(x); //输出 "null"
}
如果实参对象是一个普通数组的话,第二条console.log(x) 语句的结果绝对不会是null,在这个例子中,arguments[0] 和 x 指代同一个值,修改其中一个的值会影响到另一个。
在ECMAScript 5中移除了实参对象的这个特殊特性。在严格模式下还有一点(和非严格模式下相比)不同,在非严格模式中,函数里的arguments仅仅是一个标识符,在严格模式中,它变成了一个保留字。严格模式中的函数无法使用arguments作为形参名或局部变量名,也不能给arguments赋值。
callee和caller属性
除了数组元素,实参对象还定义了callee和caller属性。在ECMAScript 5严格模式中,对这两个属性的读写操作都会产生一个类型错误。而在非严格模式下,ECMAScript标准规范规定callee属性指代当前正在执行的函数。caller是非标准的,但大多数浏览器都实现了这个属性,它指代调用当前正在执行的函数的函数。通过caller属性可以访问调用栈。callee属性在某些时候会非常有用,比如在匿名函数中通过callee来递归地调用自身。
var factorial = function(x) {
if (x <= 1) return 1;
return x * arguments.callee(x - 1);
}
属性
callee
指代当前正在执行的函数。
length
传递给函数的参数个数,以及Arguments对象中数组元素的个数。
Arguments.callee
arguments.callee指代当前正在执行的函数。通过它可以引用匿名函数自身。该属性只定义在函数体中。
//在匿名函数内使用callee属性来引用匿名函数自身,
//以便实现递归
var factorial = function(x) {
if (x < 2) return 1;
else return x * arguments.callee(x - 1);
}
var y = factorial(5); //返回120
Arguments.length
传给函数的参数个数
Arguments对象的length属性表示传给当前函数的参数个数。该属性只定义在函数体中。
// 使用Arguments对象来检查传入参数个数的正确性
function check(args) {
var actual = args.length; //实际的参数个数
var expected = args.callee.length; //期待的参数个数
if (actual != expected) { //如果不相等,则抛出异常
throw new Error("参数个数有误:期望值:" + expected + ";实际值:" + actual);
}
}
//演示如何使用check()方法的示例函数
function f(x,y,z) {
check(arguments); //检查参数个数的正确性
return x + y + z; //正常执行该函数的剩余代码
}
第一次写博客,有问题还请麻烦指出,以后还会持续更新原生js的知识点。