函数的形参和实参-Web前端开发之Javascript-万博

371 阅读6分钟

函数的形参和实参:

参数有形参(parameter)和实参(argument)的区别,形参相当于函数中定义的变量,实参是在运行时的函数调用时传入的参数。

ECMAScript函数的参数与大多数其他语言中函数的参数有所不同。ECMAScript中的函数定义并未指定函数形参的类型,函数调用也未对传入的实参值做任何类型检查,甚至不检查传入形参的个数;也就是说,即便定义的函数只接收两个参数,在调用 这个函数时也未必一定要传递两个参数,可以传递一个、三个甚至不传递;在实际场景中,需要处理当调用函数时的实参个数和声明的形参个数不匹配的情况,也会测试函数的实参的类型,以避免非法的实参传入函数;

可选形参:

当实参比形参的个数要少时,剩下的形参都将设置为undefined值;为了让实参与形参保持较好的适应性,有必要为可选形参设置一个合理的默认值;如:

又如:

说明:当设置可选参数时,一定要把可选参数放到形参列表的最后,因为不能省略第一个参数(定参)并传入第二个实参;如果第一个参数(定参)不存在或不使用,也需要显式的传入undefined,真实的场景是传入一个无意义的占位符null;

形参个数:

函数本身的length属性,只读,它代表函数的形参个数,即函数期望传入的实参个数,如:

function sum(a,b,c){

console.log(sum.length); // 3

}

sum();

console.log(sum.length); // 3

实参对象(arguments):

ES函数的参数有自己独特的特点,即当调用函数时传入的实参个数超过函数定义的形参个数时,没有办法直接获得超出的实参的值,但可以使用实参对象arguments来获取;

在函数体内,arguments是指向实参对象有的引用,其是一个类数组对象(应该是一个集合);函数接收的始终都是这个数组,而不关心数组中包含哪些参数;即使没有传递参数,这个数组也存在,只不过是包含0个元素的数组;

function func(a,b){

console.log(arguments);

}

func();

func(1,2,3,4,5);

arguments对象只是与数组类似,它并不是Array的实例;可以使用方括号语法访问它的每一个元素(即第一个元素是arguments[0],第二个元素是arguments[1],以此类推),使用length属性来确定传递进来多少个参数,即length属性说明调用函数时实际传递的参数个数;;

如,不显式地使用命名参数:

function sayHi(){

console.log("传入了:" + arguments.length + "个参数");

console.log("Hello,"+arguments[0]+","+arguments[1]);

}

//sayHi();

sayHi("wangwei","欢迎你来学习");

说明:在ECMAScript中,命名的参数只提供便利,但不是必需的;另外,在命名参数方面,其他语言可能需要事先创建一个函数签名,而将来的调用必须与该签名一致;但在ECMAScript中,没有这些规定,解析器不会验证命名参数,因此可以使用arguments对象来验证所传递的参数是否符合函数要求;如:

说明:在某些时候,没有必要检查实参的个数,因为JS的默认行为是可以满足需要的,如省略的实参都是undefined,多出的参数自动省略。

验证形参与实参的个数,如:

可以利用arguments对象,让函数能够接收任意个数并分别实现适当的功能,如:

// 根据实参,返回最大值

function max(/* ... */){

var max = Number.NEGATIVE_INFINITY;

for(var i = 0; i< arguments.length;i++)

    if(arguments[i] > max) max = arguments[i];

return max;

}

var largest = max(1,10,100,2,3,1000,4,5,10000,6);

console.log(largest); // 10000

类似于这种可以接收任意个数的实参,这种函数也被称为“不定实参函数”,这个术语来自C语言。

但真正的不定实参的个数不能为零,其应用的场景是:该函数包含固定个数的命名和必须的参数,以及随后个数不定的可选实参,即arguments对象可以与命名参数一起使用;

arguments并不是真正的数组,它是一个对象,其数组元素是函数实参的别名;arguments的值永远与对应命名参数的值保持同步;

说明:这并不是说读取这两个值会访问相同的内存空间,它们的内存空间是独立的,但它们的值会同步;即两者本质上是不同的,其使用的是映射的关系;

注:在严格模式下,重写arguments的值会失效,但不会导致语法错误;

实参类型:

Javascript是一门弱类型语言,所以函数中的形参并没有类型声明,并且在传入参数前也未做任何类型检查,虽然JS可以进行数据类型的自动转换,但在某些时候(类型不同,不会导致语法错误,但在程序运行时有可能导致错误),函数还是希望得到一个类型明确的参数值,此时,应当对所传入的参数进行类型的检查,如:

又如:扩大累加的数据类型:

没有重载:

ECMAScript函数不能像传统意义上那样实现重载;而在其他语言中,可以为一个函数编写两个定义,只要这两个定义的签名(参数的类型和数量)不同即可;ECMAScript函数没有签名,因为其参数是由包含零或多个值的数组来表示的;而没有函数签名,真正的重载是不可能做到的;

如果定义了两个名字相同的函数,则只有后定义的有效,如:

function show(){alert("ok")};

function show(){alert("wangwei")};

show();

说明:即是第二个把第一个覆盖了;

var addNum = function(num){return num + 100;};

addNum = function(num){return num + 200;};

模拟重载:可以通过检查传入函数中参数的类型和数量并作出不同的反应,可以模拟方法的重载;

callee和caller属性:

arguments对象除了拥有数组元素外,还定义了callee和caller属性;

callee属性指向当前正在执行的函数,在某些时候非常有用,如在一个匿名函数中使用递归;但在严格模式下会抛出错误,所以,尽量避免使用callee属性,可以为函数明确定义一个名称;

caller是非标准的,但大多数浏览器都实现了这个属性,它指向调用当前函数的函数,在ES5中被移弃了,其始终会返回undefined,不会报错。

将对象用做实参:

可以采用将对象作为实参,该对象的属性就是实际需要的实参值,并且参数的顺序就无关紧要了,而且还可以方便的设置缺省参数的默认值;作为实参的对象,一般采用键/值对的方式进行定义;如: