美文网首页让前端飞程序员
JavaScript当中的this究竟是个啥?

JavaScript当中的this究竟是个啥?

作者: 张培跃 | 来源:发表于2018-06-18 13:38 被阅读11次

    对于JS的初学者而言,JS当中的this指向很难让人摸准其脉络,经常会给你一种模糊美、朦胧美的感脚!因为this并不是固定不变的,它会根据自身所执行的环境的不同而不同。而且在开发的过程中,经常因为对this的不了解出现这样或那样的错误!所以搞定this的指向是非常非常有必要的!

    与其它语言当中的this不同的是,我们JS当中的this总是指向一个对象。而具体是指向哪一个对象,则要看其运行时是基于哪一个函数的执行环境所动态绑定的。

    注意:this的指向并不是函数被声明时的环境。

    具体到实际开发中,this的指向大致可以分为以下几种:

    1、作为普通函数调用

    当你的函数不是作为对象的属性来调用时,即是我们经常说的普通函数调用。此时的this为全局对象,而JS当中的全局对象指的是window。
    作为普通对象调用:

    //定义一个全局变量age
    var age=18;
    //声明一个全局函数getAge
    function getAge(){
        return this.age;
    }
    //因为是全局环境内调用的getAget函数所以指向的对象为window
    console.log(getAge());//18
    //你也可以这样写
    console.log(window.getAge());//18
    

    以上代码中,getAge方法在全局window下调用,所以getAge方法内的this指向的是window。为了更好的验证这一点,咱们再来对以上代码修改如下:

    //声明一个全局函数getAge
    function getAge(){
        //由于该函数在全局环境(window)下调用,所以this为window
        this.age=81;//为this指向的window对象添加属性age
    }
    getAge();//全局调用函数getAge()
    console.log(age);//81
    //也可以这样输出
    console.log(window.age);//81
    

    以上代码中声明了一个全局函数getAge。由于该函数在全局环境(window)下调用,所以this为window。然后通过this.age为window对象增加一个age属性。所以在调用完该函数后进行console.log(window.age)输出的结果为81。

    2、函数作为对象的属性来调用:

    如果函数作为对象的属性来调用,函数内的this为调用函数的对象。

    var obj={
        //obj属性age
        age:12,
        //obj方法getAge
        getAge:function(){
            return this.age;
        }
    }
    //全局属性age
    var age=13;
    //全局方法getAge
    function getAge(){
        return this.age;
    }
    //在obj对象下调用getAge(),this代表的是obj
    console.log(obj.getAge());//12
    

    在全局环境下,this代表的是window。所以调取的方法为全局方法getAge。又因为getAge是在window下调用的,所以内部this指向的是window对象。最终输出结果为13

    var obj={
        //obj属性age
        age:12,
        //obj方法getAge
        getAge:function(){
            return this.age;
        }
    }
    //全局属性age
    var age=13;
    //全局方法getAge
    function getAge(){
        return this.age;
    }
    //在全局环境下,this代表window,所以下面可以理解为window对象下调用全局getAge
    console.log(this.getAge());//13
    

    接下来看种丢失掉this的情况,换言之,this的指向发生改变。我们先来看下面的代码

    var obj={
        //obj属性age
        age:12,
        //obj方法getAge
        getAge:function(){
            return this.age;
        }
    }
    //全局属性age
    var age=13;
    //全局方法getAge
    function getAge(){
        return this.age;
    }
    //在obj对象下调用getAge(),this代表的是obj
    console.log(obj.getAge());//12
    //将obj下的函数getAge赋值给fn。
    var fn=obj.getAge;
    //在全局环境(window) 下调用fn,this代表的是window
    console.log(fn());//13
    

    当调用obj.getAge时,getAge方法是作为obj对象的属性来调用的。输出结果为12。当将obj.getAge赋值给一个变量fn时,因为fn的调用是在全局环境下调用的,所以this指向的是window,输出结果为13。
    将代码汇总如下,认真看看:

    var obj={
        //obj属性age
        age:12,
        //obj方法getAge
        getAge:function(){
            return this.age;
        }
    }
    //全局属性age
    var age=13;
    //全局方法getAge
    function getAge(){
        return this.age;
    }
    //在obj对象下调用getAge(),this代表的是obj
    console.log(obj.getAge());//12
    //在全局环境下,this代表window,所以下面可以理解为window对象下调用全局getAge
    console.log(this.getAge());//13
    //将obj下的函数getAge赋值给fn。
    var fn=obj.getAge;
    //在全局环境(window) 下调用fn,this代表的是window
    console.log(fn());//13
    
    3、DOM对象的事件函数

    DOM对象的事件函数内的this指向的是该DOM对象,看以下代码:

    <body>
        <div id="myDiv">点我吧!</div>
    </body>
    <script>
        //为id为"myDiv"增加点击事件
        document.getElementById("myDiv").onclick=function(){
            //this为div
            console.log(this.id);//myDiv
        }
    </script>
    

    在事件函数内添加一个子函数_fn,该子函数内的this指向的是window:

    <body>
        <div id="myDiv">点我吧!</div>
    </body>
    <script>
        var id="window";
        document.getElementById("myDiv").onclick=function(){
            function _fn(){
                console.log(this.id);//window
            }
            _fn();
        }
    </script>
    

    但往往我们需要的是让它指向触发事件的DOM对象,此时有一种解决方法可以作为参考:

    <body>
        <div id="myDiv">点我吧!</div>
    </body>
    <script>
        var id="window";
        document.getElementById("myDiv").onclick=function(){
            var _this=this;//保存对myDiv的引用
            function _fn(){
                console.log(_this.id);//myDiv
            }
            _fn();
        }
    </script>
    
    4、构造函数

    在JS当中并没有类的概念,但是我们可以通过构造函数来创建对象,而且JS也提供了new操作符,使构造函数看起来更像是一个类!
    构造函数与普通函数的异同:构造函数与普通函数的个表是一样的,它们的区别在于调取的方式。当用new操作符调用函数时,该函数为构造函数,否则为普通函数。

    function Box(){
        this.age=14;
    }
    var obj=new Box();
    console.log(obj.age);//14
    

    通过new来调用构造函数时的执行流程如下:

    • new 构造函数(),隐式执行了new Object();
    • 将构造函数的作用域给新对象(即new Object()创建出的对象),函数体内的this就代表这个新对象。
    • 执行构造函数的语句。
    • 隐式直接返回新对象。
      需要注意的是构造函数如果直接返回一个对象,那么执行返回的对象就不是我们所期待的this:
    function Box(){
        this.age=14;
        return {
            age:16
        }
    }
    var obj=new Box();
    console.log(obj.age);//16
    
    5、通过call与apply改变this的指向

    通过call与apply可以动态的改变函数内的this

    //声明一个全局变量color
    var color="red";
    //声明一个全局对象obj,为 obj添加一个属性color值为yellow
    var obj= {
        color: "yellow"
    }
    //添加一个构造函数
    function Fn(){
        this.color="blue";
    }
    //普通函数
    function getColor(){
        console.log(this.color);
    }
    getColor();//red
    getColor.call(window);//red
    getColor.call(this);//red
    getColor.call(obj);//yellow
    getColor.call(new Fn());//blue
    

    以上代码通过call来改变函数体内this的指向,以上代码用apply也是可以实现相同的功能。只需要将call改变apply即可:

    var color="red";
    var obj= {
        color: "yellow"
    }
    function Fn(){
        this.color="blue";
    }
    function getColor(){
        console.log(this.color);
    }
    getColor();//red
    getColor.apply(window);//red
    getColor.apply(this);//red
    getColor.apply(obj);//yellow
    getColor.apply(new Fn());//blue
    

    call与apply的用法是一样,区别仅在于传入的参数形式不同。

    var num=5;
    function fn(num1,num2){
        console.log(num1+num2+this.num);
    }
    var obj={
        num:8
    }
    fn.call(this,1,2);//8
    fn.call(obj,1,2);//11
    //apply 传递的参数需要用中括号进行包裹
    fn.apply(this,[3,4]);//12
    fn.apply(obj,[3,4]);//12
    

    6、通过bind指定函数内部的this

    var age=81;
    var obj={
        age:18
    }
    //指定fn函数体内的this指向window
    var fn=function(){
        console.log(this.age);
    }.bind(this);
    //指定fn2函数体内的this指向obj
    var fn2=function(){
        console.log(this.age);
    }.bind(obj);
    fn();//81
    fn2();//18
    

    好了,今天就先到这里吧!


    相关文章

      网友评论

        本文标题:JavaScript当中的this究竟是个啥?

        本文链接:https://www.haomeiwen.com/subject/dizgeftx.html