JS是脚本语言,相对于其他像是JAVA,C等语言还不够成熟,作用域也就没有其他语言那么完善,所以this的问题在开发中,特别是面向对象开发时显得尤为关键,而且极易弄混,下面来谈谈this在不同的位置有着什么不同的指向
-
全局中的this
console.log(this);//window
function abc() {
console.log(this);//window
}
abc();
全局中的this,都指向window
-
事件中的this
var div=document.createElement("div");
document.body.appendChild(div);
div.addEventListener("click",clickHandler);
function clickHandler(e) {
console.log(this);//div 是e.currentTarget,被侦听的对象
}
什么是事件,当前这个函数,在addEventListener中被传入第二个参数,当前这个函数有且仅有一个参数,是e,并且这个e是基于event的对象在事件中,this永远指向的是e.currentTarget,就是被侦听的对象
-
混入的this
function getsum(num) {
this.a+=num;
}
var obj={a:0};
var obj1={a:10};
var obj2={a:20};
getsum.call(obj,10);//a=10
getsum.apply(obj1,[10]);//a=20
getsum.bind(obj2)(10);//a=30;
混入的this,就是使用call、apply和bind方法,代替掉原有函数中的this,所以混入的this,就是代表这个混入的对象
-
对象中的this
var obj3={
a:10,
c:function () {
// this--->obj3
console.log(this.a);
}
}
对象中的this也很明显,就是指的这个对象
-
类中的this
ES6:
class Box{
constructor(){
this.num=3;
}
play(){
// this--->obj5 也就是通过new实例化的对象
// console.log(this.num);
console.log(this===obj5);
}
}
let obj5=new Box();
obj5.play();
let obj6=new Box();
obj6.play();
ES5:
function Box() {
this.num=3;
}
Box.prototype={
play:function () {
console.log(this.num);
}
};
var obj7=new Box();
obj7.play();//this就是obj7
无论是在ES5还是ES6中,类中的this都是指向的这个类,也可以说是指向的通过类实例化的对象
-
混合模式中的this(重点)
看下面的代码就知道,这是一个最简单的混合模式的类了,类中含有点击事件,也就是说点击事件中的this和类中的this会有混淆。在类中,也就是在类的构造函数和原型对象的一般方法中,this都是指向Ball,在方法中调用类的属性和方法时,都要在前面加上this.才能引用,比如你要使用别的方法,就要用this.clickHandler才行,这时的this就是指向Ball,但是下面就有一个点击函数了,在这个函数中是不能直接调用到Ball类的,只能调用到他侦听的对象,这个局部的div,这时候要想要调用到Ball,使用Ball的方法和属性,就必须要曲线救国,下面提供两种常见的方法
第一种:
function Ball() {
}
Ball.prototype={
num:5,
clickBind:null,
createBall:function () {
var div=document.createElement("div");
document.body.appendChild(div);
div.style.width="50px";
div.style.height="50px";
div.style.backgroundColor="red";
this.clickBind=this.clickHandler.bind(this);
div.addEventListener("click",this.clickBind);
return div;
},
clickHandler:function (e) {
this.num++;
console.log(this.num);
if(this.num>=8){
e.currentTarget.removeEventListener("click",this.clickBind);
}
}
};
第一种方法的原理就是混入,用bind混入,原因是bind不会自己执行函数,把原先的点击函数的this混入成这个类,那么在点击函数中的this就不再指向原先的div了,就指向混入的对象,也就是这个Ball了。
第二种:
function Ball() {
}
Ball.prototype={
num:5,
createBall:function () {
var div=document.createElement("div");
document.body.appendChild(div);
div.style.width="50px";
div.style.height="50px";
div.style.backgroundColor="red";
div.self=this;
div.addEventListener("click",this.clickHandler);
return div;
},
clickHandler:function (e) {
this.self.num++;
console.log(this.self.num);
if(this.self.num>=8){
this.removeEventListener("click",this.self.clickHandler);
}
console.log("aaa");
}
};
var ball=new Ball();
ball.createBall();
第二种方法是最常使用的方法,原本点击事件中的this指向div,这个保持不变,给div添加一个新的属性self(可随意定),让这个属性的值为this,这个this是在类的方法中,所以这个this指的就是Ball,也就说div的属性self就是Ball,这样在点击事件函数中不能直接调用Ball,但是可以通过调用div.self也就是在事件函数中的this.self来调用到Ball了。