var name="XL";
function Person(name){
this.name=name;
this.sayName=function(){
setTimeout(function(){
console.log("my name is "+this.name);
},50)
}
}
var person=new Person("xl");
person.sayName() //输出 “my name is XL”;
//这里的setTimeout()定时函数,相当于window.setTimeout(),由window这个全局对象对调用,因此this的指向为window, 则this.name则为XL
那么如何才能输出"my name is xl"呢?
var name="XL";
function Person(name){
this.name=name;
this.sayName=function(){
setTimeout(function(){
console.log("my name is "+this.name);
}.bind(this),50) //注意这个地方使用的bind()方法,绑定setTimeout里面的匿名函数的this一直指向Person对象
}
}
var person=new Person("xl");
person.sayName(); //输出 “my name is xl”;
这里setTimeout(function(){console.log(this.name)}.bind(this),50);,匿名函数使用bind(this)方法后创建了新的函数,这个新的函数不管在什么地方执行,this都指向的Person,而非window,因此最后的输出为"my name is xl"而不是"my name is XL"
var name="XL";
function Person(){
this.name="xl";
this.showName=function(){
console.log(this.name);
}
setTimeout(this.showName,50);
}
var person=new Person(); //输出 "XL"
//在setTimeout(this.showName,50)语句中,会延时执行this.showName方法
//this.showName方法即构造函数Person()里面定义的方法。50ms后,执行this.showName方法,this.showName里面的this此时便指向了window对象。则会输出"XL";
修改上面的代码:
var name="XL";
function Person(){
this.name="xl";
var that=this;
this.showName=function(){
console.log(that.name);
}
setTimeout(this.showName,50)
}
var person=new Person(); //输出 "xl"
//这里在Person函数当中将this赋值给that,即让that保存Person对象,因此在setTimeout(this.showName,50)执行过程当中,console.log(that.name)即会输出Person对象的属性"xl"
匿名函数:
var name="XL";
var person={
name:"xl",
showName:function(){
console.log(this.name);
}
sayName:function(){
(function(callback){
callback();
})(this.showName)
}
}
person.sayName(); //输出 XL
var name="XL";
var person={
name:"xl",
showName:function(){
console.log(this.name);
}
sayName:function(){
var that=this;
(function(callback){
callback();
})(that.showName)
}
}
person.sayName() ; //输出 "xl"
//匿名函数的执行同样在默认情况下this是指向window的,除非手动改变this的绑定对象
Eval函数
该函数执行的时候,this绑定到当前作用域的对象上
var name="XL";
var person={
name:"xl",
showName:function(){
eval("console.log(this.name)");
}
}
person.showName(); //输出 "xl"
var a=person.showName;
a(); //输出 "XL"
本文主要解释在JS里面this关键字的指向问题(在浏览器环境下)。
首先,必须搞清楚在JS里面,函数的几种调用方式:
但是不管函数是按哪种方法来调用的,请记住一点:谁调用这个函数或方法,this关键字就指向谁。
接下来就分情况来讨论下这些不同的情况:
普通函数调用
在这段代码中
person
函数作为普通函数调用,实际上person
是作为全局对象window
的一个方法来进行调用的,即window.person()
; 所以这个地方是window
对象调用了person
方法,那么person
函数当中的this
即指window
,同时window
还拥有了另外一个属性name
,值为xl
.同样这个地方
person
作为window
的方法来调用,在代码的一开始定义了一个全局变量name
,值为xl
,它相当于window
的一个属性,即window.name="xl"
,又因为在调用person
的时候this
是指向window
的,因此这里会输出xl
.作为方法来调用
在上面的代码中,普通函数的调用即是作为
window
对象的方法进行调用。显然this
关键字指向了window
对象.再来看下其他的形式
再换种形式:
作为构造函数来调用
new操作符
person
里面首先创建一个空对象o,将o的proto指向Person.prototype完成对原型的属性和方法的继承Person.call(o,name)
这里即函数Person
作为apply/call
调用(具体内容下方),将Person
对象里的this
改为o,即完成了o.name=name
操作返回对象o。
因此
person("xl")
返回了一个继承了Person.prototype
对象上的属性和方法,以及拥有name
属性为"xl"的对象,并将它赋给变量personB
. 所以console.log(personB.name)
会输出"xl"call/apply方法的调用
在JS里函数也是对象,因此函数也有方法。从Function.prototype上继承到
Function.prototype.call/Function.prototype.apply
方法call/apply
方法最大的作用就是能改变this
关键字的指向.Obj.method.apply(AnotherObj,arguments);
FruitB
调用fruitA
的change
方法,将fruitA
中的this
绑定到对象FruitB
上。Function.prototype.bind()方法
那么如何才能输出
"my name is xl"
呢?这里
setTimeout(function(){console.log(this.name)}.bind(this),50);
,匿名函数使用bind(this)
方法后创建了新的函数,这个新的函数不管在什么地方执行,this
都指向的Person
,而非window
,因此最后的输出为"my name is xl"而不是"my name is XL"另外几个需要注意的地方:
setTimeout/setInterval/匿名函数执行
的时候,this
默认指向window对象
,除非手动改变this的指向。在《javascript高级程序设计》当中,写到:“超时调用的代码(setTimeout
)都是在全局作用域中执行的,因此函数中的this的值,在非严格模式下是指向window对象,在严格模式下是指向undefined”。本文都是在非严格模式下的情况。修改上面的代码:
匿名函数:
Eval函数
该函数执行的时候,this绑定到当前作用域的对象上
箭头函数
es6
里面this
指向固定化,始终指向外部对象,因为箭头函数没有this
,因此它自身不能进行new
实例化,同时也不能使用call, apply, bind
等方法来改变this
的指向参考资料