JS 函数(3)—arguments对象

arguments对象

 

JS中的参数在内部是用一个数组来表示的。函数接收到的始终是这个数组。

在函数体内能够通过arguments对象来访问这个参数数组,从而获取传递给函数的每一个参数。

arguments对象与数组类似,可以使用方括号语法访问它的每一个元素,但它并不是Array的实例。

arguments[0]访问第一个元素、arguments[1]访问第二个元素。。。以此类推。。。

也就是说,下面三个函数的调用结果完全一样。

示例1:

1 function sayHi (name, message) {    //这是个正常的函数
2     console.log("Hello " + name + "," + message);
3 };
4 sayHi("CC","Nice to meet you!");    //Hello CC,Nice to meet you!

 

示例2:

1 function sayHi (name,message) {
2     console.log("Hello " + arguments[0] + "," + arguments[1]);    //用arguments对象访问参数数组
3 };
4 sayHi("CC","Nice to meet you!");                                  //Hello CC,Nice to meet you!

 

示例3:

1 function sayHi () {                                               //根本没有命名参数
2     console.log("Hello " + arguments[0] + "," + arguments[1]);    //用arguments对象访问参数数组
3 };
4 sayHi("CC","Nice to meet you!");                                  //Hello CC,Nice to meet you!

 

这个事实,说明了JS中函数的一个重要特点:命名参数只是提供便利,不是必需的。

arguments对象可以和命名参数一起使用。

arguments对象的值永远与对应命名参数的值保持同步;它们的内存空间是独立的,但是它们的值会同步。

 

arguments.length

通过访问arguments对象的length属性,可以获知有多少参数传递给了函数。

arguments对象的length值是由传入的参数的个数决定的,不是由定义函数时的命名参数的个数决定的。

 

示例1:根据传入的参数个数不同,利用arguments.length实现不同的功能

 1 function doAdd() {
 2     if(arguments.length === 1) {
 3         return arguments[0] + 10;
 4     }
 5     if(arguments.length === 2) {
 6         return arguments[0] + arguments[1]
 7     }
 8 }
 9 console.log(doAdd(10));        //20
10 console.log(doAdd(10, 20));    //30
View Code

 

示例2:利用arguments.length实现参数求和

1 function add() {
2     var count = arguments.length;
3     var sum = 0;
4     for (var i=0; i<count; i++) {
5         sum += arguments[i];
6     };
7     return sum;
8 };
9 add(1,2,3,4,5);    //15
View Code

 

示例3:利用arguments.length获取参数最大值

 1 function maxNum() {
 2     var count = arguments.length;        //获取参数的个数,保存到变量count
 3     var arr = [];                        //创建一个空数组arr
 4     for(var i=0; i<count; i++) {         //遍历函数参数
 5         if(arguments) {  
 6             arr[i] = arguments[i];       //将参数存入数组arr
 7         };
 8     };
 9 
10     function compare(value1,value2) {    //写一个升序排列的比较函数compare
11         if(value1<value2) {
12             return -1;                   //升序排列,如果前面的值小于后面的值,返回负数
13         } else if(value1>value2) {
14             return 1;
15         } else {
16             return 0;
17         };
18     };
19     
20     arr.sort(compare);                   //将compare传入数组的sort()方法,将数组按升序排列
21     return arr[arr.length-1]             //返回数组中的最后一个值,即为最大值
22 };
23 
24 maxNum(10,50,100,70);                    //100
View Code

 

参数始终是按值传递的,不可能通过引用传递参数。

 

arguments.callee

arguments对象有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。

递归函数是一个函数通过名字调用自身的情况下构成的,下面是一个经典的阶层函数。

 1 function x(num) {
 2     if(num<=1){
 3         return 1;
 4     } else {
 5         return num * x(num-1);
 6     };
 7 };
 8 console.log(x(5));    //120
 9 var y = x;
10 console.log(y(5));    //120
11 x = null;
12 console.log(y(5));    //error

报错的原因在于:函数的执行与函数名x紧紧耦合在一起;当x=null,即使变量y依然能够调用函数,但函数内部的x(num-1)却无法执行。

 

使用arguments.callee替代x:

 1 function x(num) {
 2     if(num<=1){
 3         return 1;
 4     } else {
 5         return num * arguments.callee(num-1);
 6     };
 7 };
 8 console.log(x(5));    //120
 9 var y = x;
10 console.log(y(5));    //120
11 x = null;
12 console.log(y(5));    //120

 

在严格模式下,使用arguments.callee会报错;可以使用命名函数表达式来达成相同的效果。

1 var factorial = function f(num){
2     if(num<=1) {
3         return 1;
4     } else {
5         return num * f(num-1);
6     };
7 }; 
8 factorial(5);    //120

 

注意:只能通过factorial()调用,不能通过f()调用。

 

函数对象的caller属性,这个属性中保存着调用当前函数的函数的引用。

1 function outer() {
2     inner();
3 };
4 function inner() {
5     alert(inner.caller);
6 };              
7 outer();

因为outer()调用了inner(),所以inner.caller就指向了outer()。

 

为了实现更松散的耦合,也可以使用arguments.callee;如下:

1 function outer() {
2     inner();
3 };
4 function inner() {
5     alert(arguments.callee.caller);
6 };              
7 outer();

 

ECMAScript还定义了arguments.caller,但在严格模式下访问会报错,即使在非严格模式下,这个值也始终是undefined。

定义这个属性是为了分清arguments.caller与函数的caller属性。

posted @ 2016-08-10 14:43  Aaron_Xiao  阅读(1128)  评论(0)    收藏  举报