關於JS類中this的指向問題
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了。