B3 方法和函数
我们在这本书之前的部分和滞后的部分都定义了很多函数并且调用了它们,Java或者C#程序员会认为函数就是方法,只是用不同的标记标识而已。在这一部分中,我们来仔细地研究一下函数可以做什么。
B3.1 一等公民--函数
函数有点像Java的方法,他们都有参数,并且在被引用的时候都有返回值,但是两者之间有一个主要的区别,Java的方法是存在与定义它的类的内部的,不能从这个类里面被分离出来,而JavaScript函数是一个独立的个体,在他自己的权力范围内,是一个一等公民(Java静态类应该是位于这两者之间,不属于对象的实例,但是还是在类的定义范围之内)。
用C语言系的程序员可能会想“啊,这个跟C++里面的函数指针很像”,确实很像,但是不完全一样。
在JavaScript中,函数是一种内置对象,像我们所期望的,它包括可执行的代码,可以被调用,但是它也是Object的一个子孙,而且可以做JavaScript对象可以做的任何事情,比方说通过名字存储属性。对于函数来讲,在其中定义另一个函数是再正常不过的事情了。
我们已经知道了怎样对函数对象进行引用,更通常的情况下,我们有可能想用一行代码来饮用一个函数,例如:
var result=MyObject.doSomething(x,y,z)
然而,函数是头等公民,而且也可以通过方法用call()来调用:
var result=MyObject.doSomething.call(MyOtherObject,x,y,z)
甚至这样:
var result=MyObject['doSomething'].call(MyOtherObject,x,y,z)
Function.call()的第一个参数在调用过程中作函数的上下文的对象,随后的参数则是函数调用的参数。Apply()在第二个参数是一个数组作为参数传递的时候稍微有点不一样,在对参数长度没有限制的时候,函数的调用具有更大的灵活性。
在这里,需要指出的是JavaScript函数的参数是没有长度限制的,调用比预定义参数个数多或者少的Java或者C#方法会产生一个编译错误。JavaScript会忽略多出来的参数,给缺少的参数指定undifined。一个特别灵活的函数应该能通过参数属性来访问参数列表,赋予默认值,抛出异常,或者进行其他处理。这可以通过getter和setter方法来实现,例如:
function area(value){
if (value){
this.area=value;
}
return this.area;
}
如果我们调用area(),那么value就是未定义的,所以什么都不执行,我们这个函数就执行了一个getter的功能,如果有值传进来,这个函数就是一个setter了。
函数变得很有意思,那么就让我们首先来利用他的独立性吧。