总的来说,函数在JavaScript中可以:
◆ 被赋值给一个变量
◆ 被赋值为对象的属性
◆ 作为参数被传入别的函数
◆ 作为函数的结果被返回
◆ 用字面量来创建
函数对象
1.1 创建函数
创建JavaScript函数的一种不长用的方式(几乎没有人用)是通过new操作符来作用于Function“构造器”:
复制代码 代码如下:
var funcName = new Function( [argname1, [... argnameN,]] body );
参数列表中可以有任意多的参数,然后紧跟着是函数体,比如:
复制代码 代码如下:
var add = new Function("x", "y", "return(x+y)");
print(add(2, 4));
将会打印结果:
6
但是,谁会用如此难用的方式来创建一个函数呢?如果函数体比较复杂,那拼接这个String要花费很大的力气,所以JavaScript提供了一种语法糖,即通过字面量来创建函数:
复制代码 代码如下:
function add(x, y){
return x + y;
}
或:
复制代码 代码如下:
var add = function(x, y){
return x + y;
}
事实上,这样的语法糖更容易使传统领域的程序员产生误解,function关键字会调用Function来new一个对象,并将参数表和函数体准确的传递给Function的构造器。
通常来说,在全局作用域(作用域将在下一节详细介绍)内声明一个对象,只不过是对一个属性赋值而已,比如上例中的add函数,事实上只是为全局对象添加了一个属性,属性名为add,而属性的值是一个对象,即function(x, y){return x+y;},理解这一点很重要,这条语句在语法上跟:
复制代码 代码如下:
var str = "This is a string";
并无二致。都是给全局对象动态的增加一个新的属性,如此而已。
为了说明函数跟其他的对象一样,都是作为一个独立的对象而存在于JavaScript的运行系统,我们不妨看这样一个例子:
复制代码 代码如下:
function p(){
print("invoke p by ()");
}
p.id = "func";
p.type = "function";
print(p);
print(p.id+":"+p.type);
print(p());
没有错,p虽然引用了一个匿名函数(对象),但是同时又可以拥有属性,完全跟其他对象一样,运行结果如下:
function (){
print("invoke p by ()");
}
func:function
invoke p by ()
1.2 函数的参数
在JavaScript中,函数的参数是比较有意思的,比如,你可以将任意多的参数传递给一个函数,即使这个函数声明时并未制定形式参数,比如:
复制代码 代码如下:
function adPrint(str, len, option){
var s = str || "default";
var l = len || s.length;
var o = option || "i";
s = s.substring(0, l);
switch(o){
case "u":
s = s.toUpperCase();
break;
case "l":
s = s.toLowerCase();
break;
default:
break;
}
print(s);
}
adPrint("Hello, world");
adPrint("Hello, world", 5);
adPrint("Hello, world", 5, "l");//lower case
adPrint("Hello, world", 5, "u");//upper case
函数adPrint在声明时接受三个形式参数:要打印的串,要打印的长度,是否转换为大小写的标记。但是在调用的时候,我们可以按顺序传递给adPrint一个参数,两个参数,或者三个参数(甚至可以传递给它多于3个,没有关系),运行结果如下:
Hello, world
Hello
hello
HELLO
事实上,JavaScript在处理函数的参数时,与其他编译型的语言不一样,解释器传递给函数的是一个类似于数组的内部值,叫arguments,这个在函数对象生成的时候就被初始化了。比如我们传递给adPrint一个参数的情况下,其他两个参数分别为undefined.这样,我们可以才adPrint函数内部处理那些undefined参数,从而可以向外部公开:我们可以处理任意参数。
我们通过另一个例子来讨论这个神奇的arguments:
复制代码 代码如下:
function sum(){
var result = 0;
for(var i = 0, len = arguments.length; i < len; i++){
var current = arguments[i];
if(isNaN(current)){
throw new Error("not a number exception");
}else{
result += current;
}
}
return result;
}
print(sum(10, 20, 30, 40, 50));
print(sum(4, 8, 15, 16, 23, 42));//《迷失》上那串神奇的数字
print(sum("new"));
函数sum没有显式的形参,而我们又可以动态的传递给其任意多的参数,那么,如何在sum函数中如何引用这些参数呢?这里就需要用到arguments这个伪数组了,运行结果如下:
150
108
Error: not a number exception
函数作用域
作用域的概念在几乎所有的主流语言中都有体现,在JavaScript中,则有其特殊性:JavaScript中的变量作用域为函数体内有效,而无块作用域,我们在Java语言中,可以这样定义for循环块中的下标变量:
public void method(){
for(int i = 0; i < obj1.length; i++){
//do something here;
}
//此时的i为未定义
for(int i = 0; i < obj2.length; i++){
//do something else;
}
}
而在JavaScript中:
复制代码 代码如下: