调用一个函数会暂停当前函数的执行,传递控制权和参数给新函数。除了声明时定义的形式参数,每个函数还接受两个附加参数: this 和 arguments。参数 this 的值取决于调用的模式。在JavaScript中一共有4中调用模式: 方法调用模式、函数调用模式、构造器调用模式和 apply 调用模式。
方法调用模式(隐式绑定)
当一个函数被保存为对象的一个属性时,我们称它为一个方法。当一个方法被调用时,this 被绑定到该对象。如果调用表达式包含一个提取属性的动作(即包含一个 .点表达式或[subscript]下标表达式),那么它就是被当做一个方法来调用。
// 创建 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 到对象的绑定发生在调用的时候。
函数调用模式(默认绑定)
当一个函数并非一个对象的属性时,它就是被当做一个函数来调用的。
var sum = add(3,4); // sum 的值为7
以此模式调用函数时,this 被绑定到全局对象。这是语言设计上的一个错误。若正确,那么当内部函数被调用时,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
如果使用严格模式(strict mode),那么全局对象无法使用默认绑定,this 会绑定到undefined
function foo() {
"use strict";
console.log(this.a);
}
var a = 2;
foo(); // TypeError: this is undefined
这里有一个微妙但是非常中亚偶的细节,虽然 this 的绑定规则完全取决于调用位置,但是只有 foo() 运行在非 strict mode 下时,默认绑定才能绑定到全局对象;严格模式下与 foo() 的调用位置无关:
function foo() {
console.log(this.a);
}
var a = 2;
(function(){
"use strict";
foo(); // 2
})();
构造器调用模式
如果在一个函数前面带上 new 来调用,那么背地里将会创建一个连接到该函数的 prototype 成员的新对象,同时 this 会被绑定到那个新对象上。
首先,我们来了解一下构造函数。在传统的面向类的语言中,“构造函数”是类中的一些特殊方法,使用 new 初始化类时会调用类中的构造函数。通常的形式为:
something = new MyClass(..);
JavaScript也有一个 new 操作符,使用方法看起来和那些面向类的语言一样,但 JavaScript 中的 new 机制实际上和面向类语言完全不同。
在 JavaScript 中,构造函数只是一些使用 new 操作符时被调用的函数。它们不属于某个类,也不会实例化一个类。实际上,它们甚至都不能说是一种特殊的函数类型,它们只是被 new 操作符调用的普通函数而已。包括内置对象函数在内的所有函数都可以用 new 来调用,这种函数调用被称为构造函数调用。实际上并不存在所谓的构造函数,只有对于函数的构造调用。
使用 new 来调用函数,会自动执行以下操作:
创建(或者说构造)一个全新的对象。
这个新对象会被执行[[原型]]连接
这个新对象会绑定到函数调用的 this
如果函数没有返回其他对象,那么 new 表达式中的函数会自动返回这个新对象
// 创建一个名为 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
Apply 调用模式
apply 方法让我们构建一个参数数组传递给调用函数,也允许我们选择 this 的值。apply 方法接收两个参数,第一个是要绑定给 this 的值,第二个就是一个参数数组。
// 构造一个包含两个数字的数组,并将它们相加
var array = [3,4];
var sum = add.apply(null,array); // 7
// 构造一个包含 status 成员的对象
var statusObject = {
status: 'A-OK';
};
// statusObject 并没有继承自 Quo.prototype,但我们可以在 statusObject 上调用 get_statuse 方法,尽管statusObject 并没有一个名为 get_status 的方法
var status = Quo.prototype.get_status.apply(statusObject); // A-OK
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。