ECMScript中最有意思的莫过于函数了。每个函数都是Funtion类型的实例,而且与其他引用类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会和某个函数绑定。下面就整理一下函数常见的性质和属性。
1、没有重载
将函数名想象成指针,有助于理解为什么ECMAScript中没有函数重载的概念。
function add(num){
return num + 10;
}
function add(num){
return num + 20;
}
var result = add(10);//30
显然,这个例子中声明了两个同名的函数,而结果则是后面的函数覆盖了前面的函数。以上代码实际上与下面的代码没什么区别。
var add = function(num){
return num + 10;
}
add = function(num){
return num + 20;
}
var result = add(10);//30
通过观察重写之后的代码,很容易明白是怎么回事了——在创建第二个函数时,实际上覆盖了第一个函数的变量add。
2、函数的内部属性
在函数的内部,有两个特殊的对象:arguments和this。
arguments
在JavaScript中,arguments是一个类数组对象。arguments非常类似Array,但实际上又不是一个Array实例。包含着传入函数的所有参数。该对象有一个callee属性,该属性是一个指针,指向拥有这个arguments对象的函数。比如非常经典的阶乘函数:
function factorial(num){
if(num = 1) return 1;
else return num * factorial(num - 1);
}
上面这样写的弊端是这个函数的执行和函数名factorial紧紧耦合到了一起,为了消除这种紧密耦合的现象。这时候就可以使用arguments.callee。
function factorial(num){
if(num = 1) return 1;
else return num * arguments.callee(num - 1);
}
this
函数内部另一个特殊的对象是this,this引用的是函数据以执行的环境对象。
window.color = "red";
var o = { color:"blue"};
function sayClolr(){
alert(this.color);
}
sayColor();//red
o.sayColor = sayColor;
o.sayColor();
在全局作用域总调用sayColor方法时,this引用是全局对象window;而当把这个函数赋给对象o并调用,this指向对象o。
此外,函数还有一个对象属性:caller。返回一个对函数的引用,该函数调用了当前函数。如果是在全局作用域中调用当前函数,它的值是null。
3、prototype
prototype属性保存它们所有实例方法的真正所在。也就是toString()等方法实际都保存在prototype名下,只不过通过各自对象的实例访问罢了。
每个函数都包含两个非继承而来的方法call() aplay()。对于 apply、call 二者而言,作用完全一样,只是接受参数的方式不太一样。例如,有一个函数定义如下:
var func = function(arg1, arg2) {
};
//就可以通过如下方式来调用:
func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])
其中 this 是你想指定的上下文,他可以是任何一个 JavaScript 对象(JavaScript 中一切皆对象),call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。
JavaScript 中,某个函数的参数数量是不固定的,因此要说适用条件的话,当你的参数是明确知道数量时用 call 。
而不确定的时候用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来遍历所有的参数。
window.color = "red";
var o = { color:"blue"};
function sayColor(){
alert(this.color);
}
sayColor();//red
sayColor.call(this);//red
sayColor.call(window);//red
sayColor.call(o);//blue
此外,还有一个方法bind()。这个方法会创建一个函数的实例,其中this值会被绑定到传给bind()函数的值。
window.color = "red";
var o = { color:"blue"};
function sayColor(){
alert(this.color);
}
var objSayColor = sayColor.bind(o);
objSayColor();//blue