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了。