函数字面量
函数对象通过函数字面量来创建
//创建一个名为 add 的变量, 并把两个数字相加的函数赋给它
var add = function(a,b){
return a+b;
}
函数字面量包括4个部分。第一个部分是保留字 function。
第二个部分是函数名,它可以被省略。 函数可以通过它的名字来递归地调用自己。
如果函数没有被命名,比如上面这个例子,它被称为匿名函数(anonymous)。
函数地第三个部分是包围在圆括号中的一组参数。多个参数用逗号隔开。这些参数的名称将被定义为函数中的变量。它们不像普通的参数
那样被初始化为undefined,而是在该函数被调用的时候初始化为实际提供的参数的值。
第4个部分是被包围在花括号中的一组语句。这些语句是函数的主体。它们在函数被调用的时候执行。
函数字面量可以出现在任何表达式被允许出现的位置。函数也可以被定义在其他函数中。通过字面量创建的函数对象包含一个连到上下文
的连接。这被称为闭包(closure)。它是JavaScript强大表现力的来源。
调用
调用一个函数会暂停当前函数的执行,传递控制权和参数给新函数。除了声明时定义的形式参数,每个函数还接收两个附加的参数:this
和arguments。参数this的值取决于调用的模式。
js一共有四种调用模式:方法调用模式、函数调用模式、构造器调用模式和apply调用模式。这些模式在如何初始化this关键参数上存在
差异。
调用运算符是跟在任何一个函数值的表达式之后的一对圆括号。圆括号中可包含零个或多个逗号形式隔开的表达式。每个表达式产生一个
参数值。每个参数值被赋予函数声明时定义的形式参数。当实际参数(arguments)的个数和形式参数(paraments)的个数不匹配时,
不会导致运行错误。如果实际参数的值过多了,超出的参数值会被忽略。如果实际参数值过少,则缺少的参数会被替换为undefined。
对参数值的类型不会进行检查:任何类型的值都可以传递给任何参数。
方法调用模式
当一个函数被保存为一个对象的属性时,我们称它为一个方法。当一个方法被调用时,this被绑定到该对象。当调用表达式包含一个提取
属性的动作(及保护你一个点表达式或者一个【subscript】下标表达式,那么它就是被当作一个方法来调用。
//创建一个 myObject对象,它有一个value属性和一个increment方法。
//increment 方法接受一个可选的参数。如果参数不是数字,那么默认的数字是1.
var myObject = {
value: 0,
increment: function(inc){
this.value += typeof inc === 'number' ? inc : 1;
}
}
myObject.increment();
documnet.writeln(myObject.value); //1
myObject.increment(2);
documnet.writeln(myObject.value); //2
方法可以使用this调用自己所属对象的属性,所以它能从对象中取值或对对象进行修改。this到对象的绑定发生在调用的时候
。这个"超级"延迟绑定(very late binding)使得函数可以对this高度复用。通过this可以取得它们所属对象的上下文称为公共方法(public method)。
函数调用模式
当一个函数并非一个对象的属性时。那么它就是被当做一个函数来调用的。
var sum = add(3,4)//sum的值为7
当此模式调用函数时,this被绑定到全局对象。这是语言设计一个错误。倘若语言设计正确的话,那么当内部函数被调用的时候,this仍然
绑定到外部函数的this,这个错误设计的后果就是方法不能利用内部函数来帮助他工作,因为内部函数被绑定到错误的值,所以不能共享
该方法对对象的访问权。但是幸运的是,有一个很容易解决的办法,如果该方法定义一个变量并给它赋值为this,那么内部函数就可以通过
这个变量访问到this。按照约定,我把这个变量命名为that。
//给myObject 增加一个double方法。
myObject.double = function(){
var that = this; //解决办法
var helper = function(){
that.value = add(that.value, that.value)
};
helper(); //以函数的形式调用 helper()
}
//以方法的形式调用double
myObject.double()
document.writeln(myObject.value); //6
构造器调用模式
JavaScript是一个基于 原型继承 的语言。这一位置对象可以直接从其他对象继承属性。该语言是无类型的。
这偏离了当前编程语言的主流风格.当前大多数语言都是基于类的语言。 尽管原型继承极富表现力,但是它并未被广泛理解。所以JavaScript提供
了一套基于类的语言类似的对象构造语法。
如果一个函数前面加上 new 来调用,那么背地里会创建一个连接到该函数的 prototype 成员的新对象,同时 this 会绑定到那个新对象上。
new行为也会改变 return 语句的行为。
//创建一个名为Quo的构造器函数。它构造一个带有 status 属性的对象。
var Quo = function(string){
this.status = string;
}
//给Quo的所有实例提供一个名为 get_status 的公共方法
Quo.prototype.get_status = function(){
return.this.status
}
//构造一个Quo实例
var myQuo = new Quo("confused");
document.writeln(myQuo.get_status());//打印显示"confused"
一个函数如果创建的目的就是为了结合new前缀来使用,那么他就被称为 构造器函数。按照约定,它们保存在以大写格式命名的变量里,
如果调用构造器函数时没有加上new,可能会发生非常糟糕的事情,既没有编译警告,也没有运行时警告,所以大写约定非常重要。
不推荐这种形式的构造器函数。
Apply调用模式
因为JavaScript是一门函数式的面向对象编程语言,所以函数可以拥有方法。
apply方法让我们构建一个参数数组传递给调用函数。它也允许我们选择 this 的值。apply方法接受两个参数,第一个是要绑定给this的值,第二个
就是一个参数数组。
//构造一个包含两个数字的数组,并将它们相加
var array = [3,4]
var sum = add.apply(null, array); //sum的值为7
//构造一个包含status成员的对象。
var statusObject = {
status: 'A-OK'
};
// statusObject并没有继承自 Quo.prototype,当我们可以statusObject上调用
// 用get_status方法,尽管statusObject并没有一个名为 status的方法
var status = Quo.prototype.get_status(statusObject);//status的值为 'A-OK'