函数的参数
JS和其他大多数语言一个较为明显的区别就在于函数参数的处理上。因为在JS中调用函数的时候,传入的参数数据类型是可以不固定的,个数也无所谓多少个。听起来很奇怪,实际上,JS中的参数在内部是用一个数组表示的,不论传入的参数属于什么数据类型,有多少个,函数接收的都是这个数组。解析器并不对数组内容进行检查。(在JS中,数组的长度是可变的,存储元素的类型也是不固定的。)
我们知道了函数参数保存在一个数组中,那么我们如何去访问这个数组呢?————通过argument对象。argument对象是函数内部的一个对象,它存储着传入函数的所有参数。类似于数组,我们可以通过argument[0],argument[1]这样的方式去访问传入的参数。(但argument并不是Array的实例!)argument拥有一个名为length的属性,该属性的值表示实际传入参数的个数。
我们来看一个例子:
function info(name, age) {
alert("hi " + name + ", you are " + age + " years old.");
}
我们定义上面的函数,然后通过如下方式调用:
info("Tom", 23);
结果会输出:
hi Tom, you are 23 years old.
以上的过程都理所当然,正如我们在Java,c/c++中一样。我们这样去调用info()函数当然没有问题,但是可能并没有理解JS中函数真正的特性。事实上,我们也可以用以下的方式来调用函数:
info("Tom");
得到以下输出:
我们只传入了一个参数,因此在访问第二个参数age的时候得到了undefined值,我们在访问数组未赋值的元素时也会返回undefined值。不论我们实际传入函数的参数是什么数据类型,有多少个参数,函数接收到的永远是那个通过arguments对象访问的数组。当我们只传入了一个参数时,访问第二个参数就得到了undefined值。
实际上,上面的info()方法我们完全可以这样写:
function info() {
alert("hi " + arguments[0] + ", you are " + arguments[1] + " years old.");
}
当我们用info(“Tom”, 23)来调用这个函数的时候,同样会得到:
hi Tom, you are 23 years old.
如果我们看得深入一点,会发现:我们在函数定义时,在圆括号中写入的命名参数,只不过是为了方便阅读,方便调用时更好地传入合适的参数,方便在函数内部更便利地使用这些参数罢了。实际上,写不写这些命名参数都不会影响函数的功能。
我们甚至可以定义这样的函数:
function math(abc, def, ghi) {
if(arguments.length == 1) {
return arguments[0];
}
if(arguments.length == 2) {
return arguments[0] + arguments[1];
}
}
于是在我们传入一个参数的时候返回该参数本身,传入两个参数的时候返回这两个参数的和。至于定义函数时参数列表是什么,根本就无所谓。
上面定义的function math(abc, def, ghi)函数,根据传入参数个数的不同执行不同的操作,有点类似于函数重载的意思了。然而JS中函数并不存在重载!为什么?
为什么JS没有重载
理解JS中为什么不存在函数重载,首先要搞清楚函数重载的概念:
函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。
我们上面说过,JS中参数列表对函数的功能是没有丝毫影响的!参数列表只是为了我们更方便地使用函数而设置的,真正调用函数时,起作用的永远是一个存放参数的数组。仅凭这一点,指望通过不同的形参列表实现函数重载就是不可能做到的。
另外,在JS中,函数实际上是Function类型的实例。函数是对象,函数名实际上就是指向函数对象的指针。所以我们在定义同名函数的时候,后定义的函数只不过是覆盖了先定义函数的引用变量罢了。
例如:
function fun(arg1) {
return arg1;
}
function fun(arg1, arg2) {
return arg1 + arg2;
}
本质上和以下代码是一样的:
function fun(arg1) {
return arg1;
}
fun = function() {
return arguments[0] + arguments[1];
}
fun变量首先指向首先定义的函数
function fun(arg1) {
return arg1;
}
然而在创建第二个函数的时候,该变量被覆盖了,重新指向新定义的函数。因此重载在JS中是不可能存在的。