##this指向哪里?
一般而言,this指向函数执行时的当前对象。
In JavaScript, as in most object-oriented programming languages, this
is a special keyword that is used within methods to refer to the
object on which a method is being invoked.——jQuery Fundamentals (Chapter 2), by Rebecca Murphey
值得注意的是:该关键字在javascript执行环境中,而非声明环境中。
什么意思呢,举例说明:
例1:
var name = 'window';
var someone = {
name : 'tom',
showName : function(){
alert(this.name);
}
var other = {
name : 'Bob',
showName : someone.showName
}
other.showName(); //Bob
结果显示Bob. this关键字虽然声明在someone.showName,但运行时是在other.showName,所以this指向other对象。所以弹出的是Bob。
##没有明确的当前对象时
在没有明确的运行时对象时,this指向全局对象(global),在浏览器环境中也就是window对象。
By default, this refers to the global object.
为什么说是全局对象(the global
object),因为非浏览器情况下(例如:nodejs)中全局变量并非window对象,而就是叫“全局变量”(the global
object)。
对与this到底指向谁,只要抓准这两点(一般而言,this指向函数执行时的当前对象,当没有明确的当前对象时,this指向全局对象)就可以慢慢弄明白!
例如对于全局变量引用的函数上有:
例2:
var name = 'window';
var Tom = {
name : 'Tom',
showName : function(){
alert(this.name);
}
}
var method = Tom.showName; //method全局变量
method(); //window
在执行到var method = Tom.showName;这一句的时候,showName是对一个方法的引用(而没有执行),而把这个引用又赋值给了全局变量method。也就是说method指向了方法function(){
alert(this.name);
}
的引用,而method是一个全局变量,所以this指向window对象。
如果它
但是对于局部变量来说:
例3:
var name = 'window';
var Tom = {
name : 'Tom',
showName : function(){
alert(this.name);
}
}
var Bob = {
name : 'Bob',
showName : function(){
var f = Tom.showName;
f();
}
}
Bob.showName();
在程序执行到Bob.showName();时,showName方法的this指向Bob对象没错,也就是说
function(){
var f = Tom.showName;
f();
}
方法的this指向Bob,如果在
var f = Tom.showName之前加上一句alert(this.name)
function(){
alert(this.name); //Bob
var f = Tom.showName;
f();
}
则会弹出’Bob’。
但方法内部方法f的this并不是指向Bob,这里没有明确说明this的指向,所以f方法的this指向window,所以执行f()
结果为’window’
setTimeout、setInterval和匿名函数
在浏览器中setTimeout、setInterval和匿名函数执行时的当前对象是全局对象window,这条我们可以看成是上一条的一个特殊情况
例4:
var name = "Bob";
var nameObj ={
name : "Tom",
showName : function(){
alert(this.name);
},
waitShowName : function(){
setTimeout(this.showName, 1000);
}
};
nameObj.waitShowName();
在程序执行到nameObj.waitShowName();这一句时,waitShowName()的this指向nameObj对象,也就是
function(){
setTimeout(this.showName, 1000);
}
里的this指向nameObj,所以this.showName才成立,如果这里没有this,而直接写showName则报错。但setTimeout实际调用的就是showName方法,方法体为{alert(this.name)},在调用它的时候没有指定this的指向,所以this指向window。所以最终结果为‘window’。
将代码改成匿名函数可能更好理解一些:
例5:
var name = "window";
var nameObj ={
name : "Tom",
showName : function(){
alert(this.name);
},
waitShowName : function(){
!function(__callback){
__callback();
}(this.showName);
}
};
nameObj.waitShowName();
在调用nameObj.waitShowName时候,我们运行了一个匿名函数,将this.showName函数作为回调函数传递进这个匿名函数,在匿名函数运行时运行回调函数,因为匿名函数的this指向window,所以当在该匿名函数中运行回调函数时,回调函数的this也指向window。
由此看来
setTimeout、可以看做一个延迟执行的
function (_callback){
_callback();
}
setInterval同理。
如上例,如果一定需要在一秒钟之后显示nameObj 对象的name属性,可以做一些调整
var name = "window";
var nameObj ={
name : "Tom",
showName : function(){
alert(this.name);
},
waitShowName : function(){
var that = this;
setTimeout(function(){
that.showName();
},1000);
}
};
nameObj.waitShowName();
这样与setTimeout的this指向window并不矛盾。setTimeout执行的具体方法是function(){ that.showName() };
that指向nameObj。并不是showName方法,所以showName方法的this指向就是它的调用者that,也就是nameObj对象。这里体现了最重要的一点:方法嵌套其实很有讲究,this并不能继承到子方法里去。
new关键字
new关键字后的构造函数中的this指向用该构造函数构造出来的新对象。
function Person(_name){
this.name = _name;
}
Person.prototype.showName = function(){
alert(this.name);
}
var tom = new Person('Tom');
tom.showName(); //Tom