前言:this参数为函数的一个参数,在面向对象编程中非常重要。在JavaScript中,它的值取决于函数调用的模式,模式不同this指向就可能不同。JavaScript中共有以下4种调用模式:
1)方法调用模式;
2)函数调用模式;
3)构造函数模式;
4)apply/call模式。
方法调用模式
当一个函数被保存为对象的一个属性时,我们称此函数为方法。因此,方法是针对对象而言,当一个方法被调用时,this被绑定到该对象。通过obj.dosth或者obj[dosth]的方式,可以实现方法调用。如下:
var obj ={
value:3,
dosth:function(){
return this.value;//通过obj.do()调用时,this指向obj
}
}
console.log(obj.dosth());//3
通过obj.dosth()调用方法,因此dosth方法中的this指向obj,因此this.value返回了obj.value的值
函数调用模式
当一个函数并非一个对象的属性时,那么它就是被当做一个函数来调用的。此时,相当于再全局环境中调用此函数,this指向全局对象。
var dosth = function(){
return this.value;
}
console.log(dosth());//undefined
var value= 2;
console.log(dosth());//2
以函数模式调用时this指向全局对象这一特性,可以说是一个设计错误,它会导致内部函数调用时this无法指向外部函数的this(很多情况下我们是希望指向外部函数的this)。如下:
var value = 2;
var obj ={value:3}
obj.double = function(){
var helper = function(){
this.value = this.value*2;
}
helper();
}
obj.double();
console.log("obj的value值为:"+obj.value+",window的value值为:"+value);//obj的value值为:3,window的value值为:4
可以发现,执行了obj.double()后,obj.value值并没有变化,而全局变量value的值*2了。因为helper虽然在obj.double内部,但其采用函数模式调用时,this指向的是window而不是obj。解决这个问题也很简单:
var value = 2;
var obj ={value:3}
obj.double = function(){
var that = this;//将this赋值给that
var helper = function(){
that.value = that.value*2;
}
helper();
}
obj.double();
console.log("obj的value值为:"+obj.value+",window的value值为:"+value);//obj的value值为:6,window的value值为:2
构造函数调用模式
当一个函数采用new操作符调用时,它就成为构造函数。也就是说,构造函数只是普通函数,只是在new的那一刻,其被成为构造函数。通过new操作符调用一个函数时,new操作符背后干了三件事:
1)创建一个连接到该函数的prototype成员的新对象;
2)将构造函数的作用域赋给新对象;
3)执行构造函数代码;
4)返回新对象。
通过以上第2步,this对象就指向了新对象。
apply/call调用模式
apply/call是最直观的可以看出this指向的调用模式,在apply/call中指定的第一个参数就是要绑定给this的值。同样是上面的例子,改变调用方式后,结果便不一样了。
var value = 2;
var obj ={value:3}
obj.double = function(){
var helper = function(){
this.value = this.value*2;
}
helper.call(obj);//改变调用方式
}
obj.double();
console.log("obj的value值为:"+obj.value+",window的value值为:"+value);//obj的value值为:6,window的value值为:2
不过要注意,在非严格模式下,当第一个参数为null或undefined时,this将指向window。