前言
《本文摘自JavaScript语言精髓》第四章
介绍函数四种调用模式前,我们先来了解一下函数和方法的概念,其实函数和方法本质是一样,就是称呼不一样而已。函数:如果一个函数与任何对象关系,就称该函数为函数。方法:如果一个函数作为一个对象属性存在,我们就称之为方法。接下来就可以开始今天的主体。
JS中参数this在面向对象编程中非常重要,它的值取决于调用的模式。在JS中一共有四种调用模式。方法调用模式、函数调用模式、构造器调用模式和apply调用模式。
接下来就开始进入今天的主题:
方法调用模式
首先是方法调用模式:当一个函数被保存为对象的一个属性是,我们称它为一个方法,当一个方法被调用时,this被绑定到该对象,如果一个调用表达式包含一个属性存取表达式(即一个.点表达式或者[subscript]下标表达式),那么它被当作一个方法调用。
此处方法可以使用this去访问对象,能在对象中进行取值或者修改对象。通过this可取的它们所属对象的上下文的方法称为公共方法。
函数调用模式
当一个函数并非一个对象的属性的时候,那么它被当作一个函数来调用。以此模式调用函数时,this被绑定到全局对象。这是语言设计上的一个错误。倘若语言设计正确,那么当内部函数被调用时,this应该仍然绑定到外部函数的this变量。这个设计错误的后果就是方法不能利用内部函数来帮助它工作,因为内部函数的this被绑定了错误的值,所以不能共享改方法对对象的访问权。
var add = function (a, b) {
return a + b;
};
var myObject = {
value : 0,
increment: function (inc) {
this.value += typeof inc === 'number' ? inc : 1;
}
};
myObject.increment();
console.log(myObject.value); //1
myObject.increment(2);
console.log(myObject.value); //3
myObject.double = function () {
var that = this;
var helper = function () {
that.value = add(that.value,that.value);
};
helper(); //以函数的形式调用helper,这里形式被调用时this指向全局对象,浏览器中是window,我们这里提前把this存在that里面
};
//以方法的形式调用double
myObject.double();
console.log(myObject.value);//6
或者使用bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
myObject.double = function () {
// var that = this;
var helper = function () {
this.value = add(this.value,this.value);
}.bind(this);//bind换绑this
helper();
};
//以方法的形式调用double
myObject.double();
console.log(myObject.value);
构造器调用模式
JS是一门基于原型继承的语言,这意味着对象可以直接从其他对象继承属性。如果在一个函数前面带上new来调用,那么将创建一个隐藏连接到该函数的prototype成员的新对象,同时this将绑定到那个新对象上。
function Person(){
this.name = "zhangsan";
this.age = 19;
this.sayHello = function(){
};
}
var p = new Person();
p.sayHello();
构造函数中发this与方法中一样, 表示对象, 但是构造函数中的对象是刚刚创建出来的对象
关于构造函数中return关键字的补充说明
- 构造函数中不需要return, 就会默认的return this
- 如果手动的添加return, 就相当于 return this
- 如果手动的添加return 基本类型; 无效, 还是保留原来 返回this
- 如果手动添加return null; 或return undefiend, 无效
- 如果手动添加return 对象类型; 那么原来创建的this就会被丢掉, 返回的是 return后面的对象
apply调用模式(上下文调用模式)
上下文模式中this的指向和前三种模式不一样,它的this指向可以改变,而前三种模式是固定。函数上下文在我理解就是函数作用域。基本语法:apply和call 后面都是跟两个参数
apply和call第一个参数一样:表示使用那个对象来调用函数;apply第二个参数是:是一个数组或伪数组,数组的值做为函数的参数被传入;call第二个参数是:是基本数据类型(number string boolean);案例如下:
function print(a, b, c, d){
alert(a + b + c + d);
}
function example(a, b , c , d){
//用call方式借用print,参数显式打散传递
print.call(this, a, b, c, d);
//用apply方式借用print, 参数作为一个数组传递,
//这里直接用JavaScript方法内本身有的arguments数组
print.apply(this, arguments);
//或者封装成数组
print.apply(this, [a, b, c, d]);
}