[b][color=red][size=medium]1.理解参数[/size][/color][/b]
JavaScript函数不介意传递进来多少个参数,也不在乎传进来参数是什么数据类型。也就是说,即便你定义的函数只接收两个参数,在调用这个函数时也未必一定要传递两个参数。可以传递一个、三个甚至不传递参数。你肯定在疑问为什么会这样?
原因在于JavaScript中的参数在内部是用一个数组来表示的。函数接收到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。如果这个数组中不包含任何元素,无所谓;如果包含多个元素,也没问题。实际上,在函数体内可以通过arguments对象来访问这个参数数组,从而获取传递给参数的每一个参数。
例1:
这也说明了JavaScript函数的一个重要特点:[color=red]命名的参数只提供便利,但不是必须的。[/color]
关于arguments的行为,还有一点比较有意思。[color=red]那就是它的值永远与对应命名参数的值保持同步。[/color]
例2:
因为arguments对象中的值会自动反映到对应的命名参数,即修改arguments[1],也就修改了num2.另外因为arguments的长度是由传入的参数个数决定的,不是由定义函数时的命名参数的个数决定的。即如果只传入一个参数,num2的值为undefined,那么为arguments设置的值不会反映到命名参数中。
[b][color=red][size=medium]2.没有重载[/size][/color][/b]
在java中,可以为一个函数编写两个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可,但在JavaScript中,函数没有签名,因为其参数是由半酣零或多个值的数组来表示的。而没有函数签名,真正的重载是不可能做到的。
如果在JavaScript中定义了两个名字相同的函数,则改名字只属于后定义的函数。
例3:
[b][color=red][size=medium]3.没有重载(深入理解)[/size][/color][/b]
函数实际上是对象,每个函数都是Funciton类型的实例,而且都与其他类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。
这是一种定义函数的方式——使用Function的构造函数,最后一个参数始终被看成函数体。但是不推荐使用这种定义方式,因为会导致解析两次代码:第一次是解析常规的JavaScript代码,第二次是解析传入构造函数中的字符串,从而影响性能。不过,这种语法对于理解"函数时对象,函数名是指针"的概念导师非常直观的。
由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他变量没有什么不同。换句话说,一个函数可能会有多个名字。
例4:
对例3进行重写,如下:
通过重写后,很容易看清到底是怎么回事儿——创建第二个函数时,实际上覆盖了引用第一个函数的变量addNum。也可以这样理解,即创建第二个函数后,指针addNum指向了第二个函数,不再指向第一个函数。
JavaScript函数不介意传递进来多少个参数,也不在乎传进来参数是什么数据类型。也就是说,即便你定义的函数只接收两个参数,在调用这个函数时也未必一定要传递两个参数。可以传递一个、三个甚至不传递参数。你肯定在疑问为什么会这样?
原因在于JavaScript中的参数在内部是用一个数组来表示的。函数接收到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。如果这个数组中不包含任何元素,无所谓;如果包含多个元素,也没问题。实际上,在函数体内可以通过arguments对象来访问这个参数数组,从而获取传递给参数的每一个参数。
例1:
function howManyArgs(){
alert(arguments.length);
}
howManyArgs("string",45);//2
howManyArgs();//0
howManyArgs(12);//1
这也说明了JavaScript函数的一个重要特点:[color=red]命名的参数只提供便利,但不是必须的。[/color]
关于arguments的行为,还有一点比较有意思。[color=red]那就是它的值永远与对应命名参数的值保持同步。[/color]
例2:
function doAdd(num1,num2){
arguments[1]=10;
alert(arguments[0]+num2);
}
doAdd(30,30);//40
因为arguments对象中的值会自动反映到对应的命名参数,即修改arguments[1],也就修改了num2.另外因为arguments的长度是由传入的参数个数决定的,不是由定义函数时的命名参数的个数决定的。即如果只传入一个参数,num2的值为undefined,那么为arguments设置的值不会反映到命名参数中。
[b][color=red][size=medium]2.没有重载[/size][/color][/b]
在java中,可以为一个函数编写两个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可,但在JavaScript中,函数没有签名,因为其参数是由半酣零或多个值的数组来表示的。而没有函数签名,真正的重载是不可能做到的。
如果在JavaScript中定义了两个名字相同的函数,则改名字只属于后定义的函数。
例3:
function addNum(tmp1)
{
alert(tmp1+100);
}
function addNum(tmp1,tmp2)
{
alert(tmp1+200);
}
addNum(100);//300
[b][color=red][size=medium]3.没有重载(深入理解)[/size][/color][/b]
函数实际上是对象,每个函数都是Funciton类型的实例,而且都与其他类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。
var sum = new Function("num1","num2","return num1+num2");//不推荐
这是一种定义函数的方式——使用Function的构造函数,最后一个参数始终被看成函数体。但是不推荐使用这种定义方式,因为会导致解析两次代码:第一次是解析常规的JavaScript代码,第二次是解析传入构造函数中的字符串,从而影响性能。不过,这种语法对于理解"函数时对象,函数名是指针"的概念导师非常直观的。
由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他变量没有什么不同。换句话说,一个函数可能会有多个名字。
例4:
function sum(num1,num2){
return num1+num2;
}
alert(sum(10,10));//20
var anotherSum =sum;
alert(anotherSum(10,10));//20
sum=null;
alert(anotherSum(10,10));//20
对例3进行重写,如下:
var addNum = function(tmp1){
alert(tmp1+100);
};
addNum = function(tmp1,tmp2){
alert(tmp1+200);
};
通过重写后,很容易看清到底是怎么回事儿——创建第二个函数时,实际上覆盖了引用第一个函数的变量addNum。也可以这样理解,即创建第二个函数后,指针addNum指向了第二个函数,不再指向第一个函数。