日期:2014-05-16  浏览次数:20391 次

javascript 调用函数方式 - 摘自js语言精粹
如标题, 做个笔记.

javascript 调用函数
调用一个函数将暂停当年函数的执行, 传递控制权和参数给新函数. 除了声明时定义的形式参数,
每个函数接收两个附加的参数: this 和 arguments. 参数 this 在面向对对象编程中非常重要,
它的值取决于调用的模式. 在 Javascript 中一共有四种调用模式:
方法调用模式;
函数调用模式;
构造器调用模式;
apply 调用模式.
这些模式在如何初始化关键参数 this 上存在差异.
调用运算符是跟在任何产生一个函数值的表达式之后的一对圆括号. 圆括号内可以包含零个或多个
用逗号隔开的表达式. 每个表达式产生一个参数值. 每个参数值被赋予函数声明时定义的形式参数
名. 当实际参数(arguments)的个数与形式参数(parameters)的个数不匹配时不会导致运行错误. 如
果实际参数值多了, 超出的参数值将被忽略. 如果实际参数值过少, 缺失的值将会被替换为 undefined
对参数值不会进行类型检查: 任何类型的值都可以被传递给参数.

1)方法调用模式
当一个函数被保存为对象的一个属性时, 我们称它为一个方法. 当一个方法被调用时, this 被绑定到该
对象. 如果一个调用表达式包含一个属性存取表达式(即一个 . 点表达式或[subscript]下标表达式), 那
么它被当作一个方法来调用.
// new myObject. 它有一个 value 属性和一个 increment 方法.
// increment 方法接受一个可选的参数. 如果参数不是数字, 那么默认使用数字 1.
var myObject = {
	value: 0;
	increment: function (inc) {
		this.value += typeof inc === 'number' ? inc : 1;
	}
};
myObject.increment();
document.writeln(myObject.value); // 1
myObject.increment(2);
document.writeln(myObject.value); // 3

方法可以使用 this 去访问对象, 所以它能从对象中取值或修改该对象. this 到对象的绑定发生在
调用的时候. 这个"超级"迟绑定(very late binding) 使得函数可以对 this 高度复用. 通过 this
可取得它们所属对象的上下文的方法称为公共方法.

2)函数调用模式
当一个函数并非一个对象的属性时, 那么它被当作一个函数来调用:
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.getValue()); // 6

3)构造器调用模式
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, 可能会发
生非常糟糕的事情, 既没有编译时警告, 也没有运行时警告, 所以大写约定非常重要.
我不推荐使用这种形式的构造器函数.

4)Apply 调用模式
因为 Javascript 是一门函数式的面向对象编程语言, 所以函数可以拥有方法.
apply 方法让我们构建一个参数数组并用其去调用函数. 它也允许我们选择 this 的值.
apply 方法接收两个参数.  第一个是将被绑定给 this 的值. 第二个就是一个参数数组.
// 构造一个包含两个数字的数组, 并将它们相加.
var array = [3, 4];
var sum = add.apply(null, array); // sum == 7

// 构造一个包含 status 成员的对象.
var statusObject = {
	stutus: 'A-OK'
};

// statusObject 并没有继承自 Quo.prototype, 但我们可以在 statusObject 上调用
// get_status 方法, 尽管 statusObject 并没有一个名为 get_status 的方法.

var status = Quo.prototype.get_status.apply(statusObject);
// status == 'A-OK'