在js程序中,函数是值。对函数执行typeof运算会返回字符串“fucntion”,但是函数是js的特殊的对象。因为函数也是对象,它们也可以拥有属性和方法,就像普通的对象可拥有属性和方法一样。还可以用Function()构造函数来创建新的函数对象。
【length属性】
在函数体内arguments对象的length表示传入函数的实参个数。函数本身的length属性则有不同的含义。函数的length属性是只读属性,函数定义时的形参个数即通常也是函数调用时期望传入函数的参数个数。
可以使用arguments.length 与arguments.callee.length做比较来判断传入的参数与函数定义的参数是否一致。如下
fucntion check(args){
var actual = args.length;
var expected = args.callee.length;
if(actual !== expected){
throw Error("Expected"+expected+"args; got"+actual);
}
}
function f(x,y,z){
check(arguments); //检查实参的个数
return x + y + z;
}
【prototype属性】
每个函数都包含一个prototype属性,这个属性是指向一个对象的引用,这个对象称为“原型对象”。每个函数都包含不同的原型对象。当函数用做构造函数时,新创建的对象会从原型对象上继承属性。
【call和apply方法】
这两个方法的第一个实参是要调用函数的母对象,它是调用上下文,在函数体内用this来获得对它的引用。
f.call(o);
f.apply(o);
类似于o.m = f ; //将f存储为o的临时方法
o.m(); //调用它,不传入参数
delete o.m //将临时方法删除
对于call来说,第一个调用上下文实参之后的所有实参就是要传入待调用函数的值。如,以对象o的方法的形式调用函数f(),并传入两个参数,可以用如下代码:f.call(o,1,2);
apply方法和call方法类似,但传入实参的形式和call()有所不同,它的实参都放入一个数组当中如f.apply(o,[1,2])
【bind方法】
该方法是ECMAScript5新增的方法,但在ECMAScript 3中可以轻松模拟。从字面上看,该方法的主要作用就是将函数绑定至对象。当在函数f()上调用bind()方法并传入一个对象作为参数,这个方法将返回一个新的函数(以函数调用的方式)调用新的函数将会把原始的函数f()当做o的方法来调用。传入新函数的任何实参都将传入原始函数。如:
function f(y){return this.x+y}
var o = {x:1};
var g = f.bind(o);
g(2); //=>3
可以通过如下代码轻易实现这种绑定:
//返回一个函数,通过调用它来调用o中的方法f(),传递它所有的参数
function bind(f,o){
if(f.bind) return f.bind(o)
else return function(){
return f.apply(o,arguments);
}
}
在ECMAScript3中实现bind方法,我们将这个方法,另存为Function.prototype.bind,以便所有的函数对象都继承它
if(!Function.prototype.bind){
Function.prottotype.bind = function(o){
var self = this,boundAgs = arguments;
return function(){
var args[],i;
for(i=1;i<boundAgs.length;i++)args.push(boundArgs[i]);
for(i=0;i<arguments.length;i++)args.push(arguments[i]);
return self.apply(o,args);
}
}
}
注意:bind()方法返回的函数是一个闭包,这个闭包的外部函数中声明了self和boundArgs变量,这两个变量在闭包里用到,尽管定义闭包的内部函数已经从外部函数中返回,而且调用这个闭包逻辑的时刻要在外部函数返回之后,但闭包中照样可以正确访问这两个变量。
【toString方法】
和所有js对象一样,函数也有toString()方法,ECMAScript规范规定这个方法返回一个字符串,这个字符串和函数声明语句的语法相关,实际上,大多数(非全部)的toString()方法都返回函数的完整源代码。内置函数往往返回一个类似“[native code]”的字符串。
【Function()构造函数】
不管是通过函数定义语句还是函数直接量表达式,函数的定义都要使用function关键字。
函数的定义还可以通过Function()构造函数来定义。
var f = new Function("x","y","returnx*y;") <==> var f = function(x,y){returnx*y;}
Function()构造函数可以传入任意数量的字符串实参,最后一个实参所表示的文本就是函数体,它可以包含任意的javascript语句,每两条语句之间用分号分隔。传入构造函数的其他所有实参字符串是指定函数形参的名字的字符串。如果函数没有参数,则只需要传入一个"函数体"字符串。
注意:Function()构造函数并不需要传入实参,以指定函数名。就象函数直接量一样,Function()构造函数创建一个匿名函数。
1. Function()构造函数允许js在运行时动态地创建并编译函数
2. 每次调用Function()构造函数都会解析函数体,并创建新的函数对象。如果是在一个循环或多次调用的函数中执行这个构造函数,效率会受到影响,相比之下,嵌套函数和函数定义表达式则不会每次执行时都重新编译。
3. 重点 Function()创建的函数并不是使用记法作用域,相反,函数体代码总会在顶层函数执行,正如
var scope = "global";
fucntion constructFunction(){
var scope = "local";
return new Fucntion("return scope");
}
//返回函数使用的不是局部作用域
constructFunction()(); //=>"global"
可以将Function()构造函数主为是在全局作用域中执行eval(),而eval()可以在自己的私有作用域内定义新变量和函数