JavaScript是一种基于对象的语言,即使是函数也不例外。每个函数都是一个对象,都是Function类型的实例。既然函数也是对象,那么它就和其他对象没有什么太大区别,函数对象也同样具有自己的属性和方法,函数名就是指向函数对象的指针。
我们常用的方式是函数声明的方式:
function join(str1, str2)
{
return str1 + str2;
}
我们还可以使用函数表达式的方式:
var join = function(str1, str2)
{
return str1 + str2;
}
除此之外,我们还可以使用构造函数方式:
var join = new Function("str1", "str2", "return str1 + str2");
虽然这三种方式都可以创建函数对象,但是函数声明和函数表达式有少许差别。解析器还在加载阶段就会读取函数声明,把每个作用域中的所以函数声明放在其变量对象中,所以即使在代码结构中,你将函数声明写在代码的最后面,在之前调用这个函数也不会有任何问题。但是函数表达式会在解析器执行阶段才会被解析执行,如果你在函数表示式之前调用就会出现运行时错误。对于第三种构造函数方式,建议不使用,不仅使用不方便,而且性能不如上面两种好。
函数名join存着一个指向函数对象的指针,如果将join赋值给其他变量,那么其他变量也会指向同一个函数对象,所以函数对象也属于引用类型,多个变量可以共享一个函数对象。ECMAScript没有重载的概念,正是由于函数名存的是指针,所以定义多个同名的函数,就相当于多次改变这个函数名指向的函数对象,所以最后一次定义会覆盖前面的函数定义。
arguments 和 this
在函数内部,可以使用this和arguments这个两个属性。
arguments是一个类数组对象,它以数组形式依次保存着所以传入函数的参数,除此之外arguments还有一个callee属性,callee属性指向的就是对当前函数的引用。
this是一个很特殊的对象,它会根据不同的执行环境而变化,不管执行环境怎么改变,this始终指向调用函数的执行环境,说简单点就是在调用函数的时候,函数名前面的点前面的那个对象。
例子:
var num = 1;
var obj = new Object();
obj.num = 2;
obj.getNum = getNum;
function getNum()
{
console.log( arguments ); // 用数组形式表示传入的参数[arg1, arg2, arg3...]
console.log( arguments.callee ); // 引用getNum函数对象
alert(this.num);
}
getNum(); // 弹出1,这里其实相当于window.getNum(),所以this是执行全局的window,而window的num就是全局定义的1
obj.getNum("3", "4"); //弹出2,this指向的点前面的对象即obj,obj的num就是2
函数对象的属性和方法
length:表示函数命名参数的个数;
prototype:引用函数对象的原型对象,原型保存着函数对象所有共享的方法,关于原型对象以后再具体介绍;
apply:接受两个参数,第一个是执行函数的作用域对象,第二个是参数数组。这个方法可能有点不好理解,我们上面提到函数对象有一个内部属性叫this,this指向的函数的当前作用域对象。如果函数在全局环境中被调用,那么this就指向window,如果函数被某个对象调用,那么this就指向这个对象。apply的作用实质就是改变函数对象中的this指向的对象,传入的第一个参数就是this要指向的作用域对象,当在调用apply函数的时候,无论函数在任何环境中被调用,函数中的this都指向apply的第一个参数表示的那个对象。第二个参数就是要传递给函数的参数,只是参数都被封装到一个数组中。我们来看个例子:
var str = "全局的作用域";
var obj = new Object();
obj.str = "obj的作用域";
obj.fun = function(str)
{
alert(str + " : " + this.str);
}
obj.fun.apply(this, [ "Hello" ]); // 弹出 “Hello : 全局的作用域”,因为参数this是window,所以就在全局作用域的基础上运行,参数this不是函数内部那个 this,apply是将函数内部this的值改变成参数this的值,即window对象
obj.fun.apply(obj, ["Hello"]); // 弹出“Hello : obj的作用域”,this指向obj对象
call:call和apply功能完全一样,只是第二个参数不在需要打包成数组,只需要将参数直接传给apply即可;
toString:用字符串的方式返回函数代码,因浏览器不同而异;