javascript 中函数参数的理解

来源:互联网 发布:血源诅咒捏脸数据男 编辑:程序博客网 时间:2024/05/16 03:31

 
一。理解参数


    ECMASCript 函数的参数与大多数其他语言中的函数的参数有所不同,ECMAScript函数不介意参数传递进来多少个参数,也不在乎传进来参数是什么数据类型。也就是说,即便你定义的函数接收两个参数,在调用这个函数时也未必一定要传递两个参数。可以传递一个,三个甚至不传参数,二解释器永远不会有什么怨言。之所以会这样,原因是ECMASCript中的参数在内部是用一个数组来表示的。函数接收到始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。如果这个数组中不包含任何元素,无所谓; 如果包含多个元素,也没问题。实际上,在函数体内可以通过arguments对象来访问这个参数数组,从而获取传递给函数的每一个参数。

    其实,arguments对象只是一个与数组类似(它并不是Array的实例),因为可以使用方括号语法访问它的每一个元素(即第一个元素师arguments[0],第二个元素师arguments[1],一此类推),使用length 属性来确定传递进来多少个参数。在下面的(例1)中,sayHi()函数的第一个参数的名字叫name,而该参数的值也可以通过访问argumens[0]来获取,因此,那个函数也可以向下面(例2)这样重写,即不显示地使用命名参数: 例1和例2的效果是一样的。

      

 function sayHi(name, message) {  alert("Hello "+ name + "," + message);}   例1
 
 function sayHi() {  alert("Hello "+arguments[0] + "," +message);}例2
   例1重写后的函数例2中不包含命名参数。虽然没使用name和message标示符,但函数的功能依旧。这个事实说明ECMAScript函数的一个重要特点 : 命名参数只提供便利,但不是必需的。另外,在命名参数方面,其他语言可能需要事先创建一个函数签名,而将来的调用必须与改签名一致。但在ECMAScript中,没有这些条条框框,解析器不会验证命名参数。

   通过访问arguments对象的length属性可以获知有多少个参数传递给了函数。下面这个函数会在每次调用时,输出传入其中的参数个数:

 

 function howManyArgs() {  alert("输出: "+arguments.length);}howManyArgs("string", 45); //输出:2howManyArgs();  //输出:0howManyArgs(23); //输出:1

再有如下这个例子:

 function doAdd() {   if (arguments.length == 1){    alert(arguments[0]+10);    } else if (arguments.length == 2) {        alert(arguments[0]+arguments[1]);  }}doAdd(10);    //输出10doAdd(20,20);  //输出40

   另一个与参数相关的重要的方面,就是arguments对象可以与命名参数一起使用,如下例子所示:

 function doAdd(num1, num2) {  if (arguments.length == 1) {    alert(num1+10); } else if (arguments.length == 2) {  alert(arguments[0]+num2); }}
  在重写后的这个doAdd()函数中,两个命名参数都与arguments对象一起使用。由于num1的值与arguments[0]的值相同,因此他们可以互换使用,(当然,num2和arguments[1]也是如此).

  arguments的值与对应命名参数的值保持同步。例如:

  例3:

 function doAdd(num1,num2) {    arguments[0] = 10;    alert(num1 + arguments[1]);}doAdd(3,10);  //输出 20
       每次执行这个doAdd()函数都会重写第二个参数,将第二个参数的只修改为10,。因为arguments对象中的值会自动反映到对应的命名参数,所以修改arguments[0],也就修改了num1, 结果他们的值都变成了10,。不过,这并不是说读取这两个值会访问相同的内存空间;他们的内存空间是独立的,但他们的值会同步。但这种影响是单向的;修改命名参数不会改变arguments中对应的值。另外还要记住,如果只传入一个参数,那么为arguments[1]设置的值不会反应到命名参数中。这是因为arguments对象的长度是由传入的参数个数决定的,不是由定义函数时的命名参数的个数决定的。

     关于参数还要记住最后一点: 没有传递值的命名参数将自动被赋予undefined值、这就跟定义了变量但没有初始化一样。

     严格模式对如何使用arguments对象做出了一些限制,首先,向前面(例3)中的那样赋值会变得无效,也就是说,即使把arguments[0] = 10, num1的值仍然还是undefined. 其次,重写arguments的值会导致语法错误。

     ECMAScript中的所有参数传递的都是值,不可能通过引用传递参数.

   

.ECMAScript 函数没有重载

         ECMAScript函数不能像传统意义上那样实现重载。而在其他语言(如:java)中,可以为一个函数编写两个定义,只要这两定义的签名(接受的参数的类型和数量)不同即可。如前所述,ECMAScript函数没有签名,因为其参数是由包含零个或多个值的数组表示的。(其实也可这么理解,函数的参数的个数或类型是不确定的,由传入的参数个数决定的,所以当传入实参时解释器不知道该调用哪个重载函数)而没有函数签名,真正的重载是不可能做到的。

      如果在ECMAScript中定义了两个名字相同的函数,则该名字只属于后定义的函数,请看下面的例子:

 

 function addSomeNumber(num) { return num+100;}function addSomeNumber(num) { return num+200;}var result = addSomeNumber(100);  //输出: 300

   在此,函数addSomeNumber(num) 被定义两次。由于后定义的函数覆盖了先定义的函数,因此当调用函数时,返回的结果就是300.

 

原文来自 :JavaScript 高级程序设计(第三版)

0 0
原创粉丝点击