为了账号安全,请及时绑定邮箱和手机立即绑定

JavaScript当中的this究竟是个啥?

标签:
JavaScript

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

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

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

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

1、作为普通函数调用

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

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

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

//声明一个全局函数getAgefunction 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;
    }
}//全局属性agevar age=13;//全局方法getAgefunction getAge(){    return this.age;
}//在obj对象下调用getAge(),this代表的是objconsole.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;
    }
}//全局属性agevar age=13;//全局方法getAgefunction getAge(){    return this.age;
}//在全局环境下,this代表window,所以下面可以理解为window对象下调用全局getAgeconsole.log(this.getAge());//13

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

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

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

<body>
    <div id="myDiv">点我吧!</div></body><script>
    //为id为"myDiv"增加点击事件
    document.getElementById("myDiv").=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").=function(){        function _fn(){            console.log(this.id);//window
        }
        _fn();
    }</script>

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

<body>
    <div id="myDiv">点我吧!</div></body><script>
    var id="window";    document.getElementById("myDiv").=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

//声明一个全局变量colorvar color="red";//声明一个全局对象obj,为 obj添加一个属性color值为yellowvar obj= {    color: "yellow"}//添加一个构造函数function Fn(){    this.color="blue";
}//普通函数function getColor(){    console.log(this.color);
}
getColor();//redgetColor.call(window);//redgetColor.call(this);//redgetColor.call(obj);//yellowgetColor.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();//redgetColor.apply(window);//redgetColor.apply(this);//redgetColor.apply(obj);//yellowgetColor.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);//8fn.call(obj,1,2);//11//apply 传递的参数需要用中括号进行包裹fn.apply(this,[3,4]);//12fn.apply(obj,[3,4]);//12

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

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

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



作者:张培跃
链接:https://www.jianshu.com/p/e16aec12c96c


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消