JavaScript中的Function对象
函数的类型分为三类
函数逻辑代码容器
function Add(x,y){
return x+y
}
alert(Add(2,8));
定义一个函数有三种方式
- 函数声明function foo(){}
- 函数表达式 var foo=function(){}
- Function对象 var foo=new Function
函数表达式:var example = function(){
return 1;
}
example();//1
var example = function(){
return 2;
}
example();//2
函数声明:function example(){
return 1;
}
example();//1
function example(){
return 2;
}
example();//2
在采用函数声明创建同名函数时,后创建的函数会覆盖先创建的函数。这种差别是由于JavaScript解释引擎的工作机制所导致的。JavaScript解释引擎在执行任何函数调用之前,首先会在全局作用域中注册以函数声明创建的函数,然后再依次执行函数调用。由于注册函数时,后定义的函数重写了先定义的函数,因此无论调用语句位于何处,执行的都是后定义的函数。
相反,对于函数表达式创建的函数,JavaScript解释引擎会像对待任何声明的变量一样,等到执行调用该变量的代码时才会对变量求值。由于JavaScript代码是从上到下顺序执行的,因此当执行第一个example()调用时,example函数的代码就是首先定义代码;而当执行第二个example()调用时,example函数的代码又变成了后来定义的代码。
作为对象方法
JavaScript在解析代码时,会为声明或定义的函数指定调用对象。所谓调用对象,就是函数的执行环境。如果函数体内有以关键字this声明的变量,则this引用的就是调用对象。事实上,在普通的函数中,也存在调用对象,只不过这个调用对象是默认的全局window对象而已。例如上面的例子相当于:
var Add= window.Add(26,26); // Add= 52
这说明,默认情况下,在全局作用域中定义或声明的函数的调用对象就是window。 在面向对象编程中,通常将作为对象成员的函数称为方法。
var people={}
people.name="lefter";
people.age="24 years old"
people.intro=function(){
alert(this.name+" is "+this.age)
}
people.intro();//lefter is 24years old
var animal ={}
animal .name='huahua'
animal .age='1years old';
animal .wangwang=people.intro;//对象可以借用其他对象的方法
animal .wangwang();//huahua is 1years
使用函数对象的call和apply方法,还可以动态指定函数或方法的调用对象
call 方法:调用一个对象的一个方法,以另一个对象替换当前对象(其实就是更改对象的内部指针,即改变对象的this指向的内容)
call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。
apply方法apply方法的第一个参数也是要传入给当前对象的对象,即函数内部的this。后面的参数都是传递给当前对象的参数。
对于apply和call两者在作用上是相同的,但两者在参数上有区别的。对于第一个参数意义都一样,但对第二个参数:apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,而call则作为call的参数传入(从第二个参数开始)。
如 func.call(func1,var1,var2,var3)对应的apply写法为:func.apply(func1, [var1,var2,var3])同时使用apply的好处是可以直接将当前函数的arguments对象作为apply的第二个参数传入
animal.wangwang.call(people);
或者:animal.wangwang.apply(people);
作为构造函数
function Man(name,age){
this.name= name;
this.age = age;
}
//然后可以new一个实例
var lefter=new Man("lefter",24);
创建lefter的对象的过程如下:首先,new运算符创建一个空对象({}),然后以这个空对象为调用对象调用函数Man,为这个空对象添加两个属性name和age,接着,再将这个空对象的默认constructor属性修改为构造函数的名称(即Man;空对象创建时默认的constructor属性值是Object),并且将空对象的__proto__属性设置为指向Man.prototype——这就是所谓的对象初始化。最后,返回初始化完毕的对象。这里将返回的新对象赋值给了变量lefter,除了new外还可以用这样的方式来创建。
var lefter = {};
Man.call(lefter,"lefter",24);
区别是后者新创建的lefter对象失去了通过Man.prototype属性继承其他对象的能力。只要与前面采用new运算符调用构造函数创建对象的过程对比一下,就会发现,new运算符在初始化新对象期间,除了为新对象添加显式声明的属性外,还会对新对象进行了一番“暗箱操作”——即将新对象的constructor属性重写为Man,将新对象的__proto__属性设置为指向Man.prototype。虽然手工“初始化对象”也可以将dog.constructor重写为Man,但根据ECMA262规范,对象的__proto__属性对开发人员是只读的,对它的设置只能在通过new运算符创建对象时由JavaScript解释引擎替我们完成。
JavaScript是基于原型继承的,如果不能正确设置对象的__proto__属性,那么就意味着默认的继承机制会失效:
Man.prototype.say="hellow";
lefter.say;//undefine

Comments (1)
JavaScript是基于原型继承的,如果不能正确设置对象的__proto__属性,那么就意味着默认的继承机制会失效:
Give lefter a comment