今天我要说的是JS中的this指向,首先我们应该知道在js中函数的几种调用方式:
- 普通函数调用
- 作为方法来调用
- 作为构造函数来调用
- 使用apply/call方法来调用
- Function.prototype.bind方法
- es6箭头函数
不管是通过哪种方式函数调用,我们都应该明确一点谁调用这个函数或方法,this关键字就指向谁。
1.普通函数调用
function person(){
this.name="lx";
console.log(this);//window
console.log(this.name);//lx
}
person();
console.log(window.name);//lx
在这段代码中person函数作为普通函数调用,实际上person是作为全局对象window的一个方法来进行调用的,即window.person(),所以这个地方是window对象调用了person方法,那么person函数当中的this即指window,同时window还拥有了另外一个属性name,值为lx,我在最后也输出了window.name即lx。
2.作为方法来调用
var name="lx";
var person={
name:"jay",
showName1:function(){
console.log(this.name);
}
}
person.showName1();//jay
var showName2=person.showName1;
showName2();//lx
第一个是的person对象调用showName1方法,所以this指向person对象,所以输出jay,第二个将person.showName1方法赋值给showName2变量,此时showName2变量相当于window对象的一个属性,相当于window.showName2,所以this指向的是window,输出lx
var personA={
name:"lx",
showName:function(){
console.log(this.name);//jay
}
}
var personB={
name:"jay",
sayName:personA.showName
}
personB.sayName();
这里的showName方法肃然是在personA这个对象中定义,但是调用的时候却是在personB这个对象中调用,因此this对象指向的是personB
3.作为构造函数调用
function Person(name){
this.name=name;
}
var personA=Person("lx");
console.log(personA.name); //会报错
console.log(window.name);//输出lx
//上面代码没有进行new操作,相当于window对象调用Person("lx")方法,那么this指向window对象,并进行赋值操作window.name="lx".
var personB=new Person("lx");
console.log(personB.name);// 输出lx
new操作符
function person11(name){
var o={};
o.__proto__=Person.prototype; //原型继承
Person.call(o,name);
return o;
}
var personB=person11("lx");
console.log(personB.name); // 输出 lx
上面这段代码模拟了new操作符(实例化对象)的内部过程
4.call/apply方法的调用
在JS里,函数也是对象,因此函数也有方法,从Function.prototype上继承到Function.prototype.call/Function.prototype.apply方法。
call/apply方法最大的作用就是能改变this关键字的指向。
var name="jay";
var Person={
name:"lx",
showName:function(){
console.log(this.name);
}
}
Person.showName.call(Person); //输出lx
Person.showName.call();//输出 jay
虽然showName方法定义在Person对象里面,但是使用call方法后,将showName方法里面的this指向了window,因此最后会输出jay,这里call方法里面的参数为空,默认指向window。
5. Function.prototype.bind方法
var name="jay";
function Person(name){
this.name=name;
this.sayName=function(){
setTimeout(function(){
console.log("my name is "+this.name);
},50)
}
}
var person=new Person("lx");
person.sayName(); //输出my name is jay
//这里的setTimeout()定时函数,相当于window.setTimeout(),由window这个全局对象对调用,因此this的指向为window, 则this.name则为jay
难么该怎么输出my name is lx?
var name="jay";
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("lx");
person.sayName(); //输出my name is lx
这里setTimeout(function(){console.log(this.name)}.bind(this),50);,匿名函数使用bind(this)方法后创建了新的函数,这个新的函数不管在什么地方执行,this都指向的Person,而非window,因此最后的输出为my name is lx而不是my name is jay。
这里的第六种方法是 es6箭头函数,es6的内容看的稍微有点少,理解的不是很全面,所以我就不再做详细的书写了,感兴趣的大牛可以度娘了解一下。