第3章:基本概念(函数)

函数对任何语言来说都是一个核心的概念。通过函数可以封装任意多条语句,而且可以在任何地方任何时候调用执行。ECMAScript中函数使用function关键字来声明,后跟着一组参数以及函数体。函数的基本语法如下所示:

function functionName(arg0,arg1,...agrN){
    statements
}

以下是一个函数实例:

function sayHi(name,message){
    alert("Hello " + name + "," + message);
}

这个函数可以通过其函数名来调用,后面还要加上一对圆括号和参数(圆括号中的参数如果有多个,可以用逗号隔开)。调用sayHi()函数的代码如下所示:

sayHi("Nicholas","How are you today?");

这个函数的输出结果是”Hello Nicholas,how are you today?”。函数中定义的命名参数name和message被当做了字符串拼接的两个操作数,而结果最终通过警告框显示了出来。

ECMAScript中的函数在定义时不必要指定是否返回值。实际上函数在任何时候都可以通过return 语句后跟要返回的值来实现返回值。请看下面的例子:

function sum(num1,num2){
    return num1 + num2;
]

这个sum的作用是把两个值加起来返回一个结果。我们注意到,除了return语句之外,没有任何声明表示该函数会返回一个值。调用这个函数的的实例代码如下:

var result = sum(5,10);

这个函数在执行完成return语句之后停止并立即退出。因此,位于return语句之后的任何代码永远都不会执行。例如:

function sum(num1,num2){
    return num1 + num2;
    alert("hello world");
}

在这个例子中,由于调用alert()函数的语句位于return语句之后,因此永远不会显示警告框。当然,一个函数中也可以包含多个retrun语句,如下面的例子所示:

function diff(num1,num2){
    if(num1 < num2){
        return num2 - num1;
    }else{
        return num1 -num2;
    }
}

这个例子中定义的diff()函数用于计算两个数值的差。如果第一个数比第二个数小,则用第二个数减第一个数;否则,用第一个数减去第二个数。代码的两个分支都具有自己的return语句,分别执行正确的计算。

另外,return语句也可以不带任何返回值。在这种情况下,函数在停止执行之后将返回undefined值。这种用法一般在需要提前停止函数执行而不需要返回值的情况下。比如下面的这个例子中,就不会显示警告框:

function sayHi(name,message){
    return;
    alert("Hello " + name + "," + message);
}

3.7.1 理解参数

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

其实arguments对象只是与数组类似,因为可以使用方括号语法访问它的每一个元素,使用length属性可以访问传递进来多少个参数。在前面的例子中,sayHi()函数的第一个参数的名字叫做name,而该参数的值也可以通过访问arguments[0]来获取。因此这个函数也可以像下面这样重写,即不显式地使用命名参数:

function sayHi(){
    alert("Hello " + arguments[0]+ "," + message[1]);
}

这个重写后的函数中不包含命名参数。虽然没有使用name和message标识符,但是函数的功能依旧。这个事实说明了ECMAScript函数的一个重要特点:命名的参数只提供便利,但不是必须的。另外,在命名参数方面,其他语言可能需要事先创建一个函数签名,而将来调用必须和函数前面一致。但是在ECMAScript中,没有这些跳跳框框,解析其不会验证命名参数。

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

function howManyArags(){
    alert(arguments.length);
}
howManyArgs("string",45);   // 2
howManyArgs();          // 0
howManyArgs(12);        // 1

执行以上代码会依次出现3个警告框,分别显示2、0和1。由此可见,开发人员利用这一点让函数能够接收任意个参数并分别实现适当的功能。请看下面这个例子:

function doAdd(){
    if(arguments.length == 1){
        alert(argument[0] + 10);
    }else if(arguments.length == 2){
        alert(arguments[0] + grguments[1]);
    }
}
doAdd(10);  // 20
doAdd(30,20);   // 50

函数doAdd()会在只有一个参数的情况下给参数加上10;如果有两个参数,则将那个参数简单相加并返回结果。因此,doAdd(10)会返回20,doAdd(20,30)会返回50。虽然这个特性算不上完美的重载,也足够弥补CMAScript的这一缺憾了。

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

function doAdd(num1,num2){
    if(arguments.length == 1){
        alert(num + 10);
     }else if(arguments.length == 2){
        alert(arguments[0] + arguments[1]);
     }
}

在重写后的doAdd()函数中,两个命名参数与arguments对象一起使用。由于num1的值与arguments[0]的相同,因此它们可以互换使用。

关于arguments的行为,还有一个一点非常有意思。那就是它的值与对应的命名参数的值保持同步。例如:

function addAdd(num1,num2){
    arguments[1] = 10;
    alert(arguments[0] + num2);
}

每次执行这个doAdd()函数都会重写第二个参数,讲第二个参数的值修改为10,。因为arguments对象中的值会自动映射到对象的命名参数,所以修改了arguments[1],也就修改了num2,结果他们的值都会变成10.。不过这样并不是说读取两个值都会访问相同的内存空间;他们的内存空间是独立的,但是它们的值会同步。另外要记住,如果只传入一个参数,那么为arguments[1]的值不会影响到命名参数。这是因为arguments对象的长度有传入参数的个数决定,不是由定义函数时候的参数个数决定的。

关于参数还要多记住一点:没有传递至的命名参数都将被赋予undefined的值。这就跟定义变量但是没有初始化一样,例如:如果给doAdd()函数传入一个参数,则num2中就会保存undefined的值。

严格模式对如何使用arguments对象做了一些限制。首先,像前面的例子中那样赋值会变得无效。也就是说,即使把arguments[1]设置为10,num2的值仍然还是undefined。其次,重写arguments的值就会导致语法错误。

3.7.2 没有重载

ECMAScript函数不能像传统意义上那样实现重载。而在其他语言中,可以作为一个函数两个定义,只要这两个定义的签名不同即可。如前面所述,ECMAScript函数没有签名,因为其参数是由包含零个或者多个值的数组来表示的。而没有函数签名,真正的重载是不能做到的。

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

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

在此,函数addSomeNumber()被定义了两次。第一个版本参数加100,而第二个版本给参数加200。由于后定义的覆盖了先定义的函数,因此当最后一行代码调用了这个函数,返回的结果就是300。

如前面所述,通过检查传入参数的类型和数量做出不同的反映,可以模仿方法的重载。

猜你喜欢

转载自blog.csdn.net/s_a_g_e/article/details/80227876