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

猜你喜欢

转载自blog.csdn.net/qq_43119195/article/details/83903878