javaScript的this指向总结(原创)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javaScript的this指向总结(原创)相关的知识,希望对你有一定的参考价值。

    在javascript中this的指向一直是前端同事的心头病,也同时是各面试题的首选,现在我们就来总结一下js中this的指向。首先需要了解一下几个概念:

1:全局变量默认挂载在window对象下
2:一般情况下this指向它的调用者
3:es6的箭头函数中,this指向创建者,并非调用者
4:通过call、apply、bind可以改改变this的指向

下面我们具体分析一下

1:在函数调用时

  (非严格模式)

1     const func = function () {
2         console.log(this);
3         const func2 = function () {
4             console.log(this);
5         };
6         func2(); //Window
7     };
8     func();  //Window

   (严格模式)

1     ‘use strict‘
2     const func = function () {
3         console.log(this);
4         const func2 = function () {
5             console.log(this);
6         };
7         func2(); //undefined
8     };
9     func();  //undefined 

     结合第四和第一两条规则:func这个函数是全局的,默认挂载在window对象下,this指向它的调用者即window,所以输出window对象,但是在严格模式下,this不允许指向全局变量window,所以输出为undefined(func2在函数直接调用时默认指向了全局window,其实这属于javascript设计上的缺陷,正确的设计方式是内部函数的this 应该绑定到其外层函数对应的对象上,为了规避这一设计缺陷,聪明的 JavaScript 程序员想出了变量替代的方法,约定俗成,该变量一般被命名为 that。这种方式在接下来会讲到)。

2:作为对象方法

 1     const user = {
 2 
 3         userName: ‘小张‘,
 4         age: 18,
 5         selfIntroduction: function () {
 6             const str = ‘我的名字是:‘ + this.userName + ",年龄是:" + this.age;
 7             console.log(str);
 8 
 9             const loop = function () {
10                 console.log(‘我的名字是:‘ + this.userName + ",年龄是:" + this.age);
11             };
12 
13             loop();     //我的名字是:undefined,年龄是:undefined
14 
15         }
16     };
17 
18     user.selfIntroduction();    //我的名字是:小张,年龄是:18

    按照咱的第一条规则,this指向他的调用者,selfIntroduction()方法的调用者是user,所以在selfIntroduction()方法内部this指向了他的父对象即user,而loop方法输出的为undefined的原因就是我在上面所说的javascript的设计缺陷了,在这种情况下,我们通常选择在selfIntroduction()方法里将this缓存下来。

 1     const user = {
 2         userName: ‘小张‘,
 3         age: 18,
 4         selfIntroduction: function () {
 5             const str = ‘我的名字是:‘ + this.userName + ",年龄是:" + this.age;
 6             console.log(str);
 7 
 8             const that=this;
 9 
10             const loop = function () {
11                 console.log(‘我的名字是:‘ + that.userName + ",年龄是:" + that.age);
12             };
13 
14             loop();     //我的名字是:小张,年龄是:18
15 
16         }
17     };
18 
19     user.selfIntroduction();    //我的名字是:小张,年龄是:18

此时loop的this指向就理想了。

 1     const user={
 2 
 3         userName:‘小张‘,
 4         age:18,
 5         selfIntroduction:function(){
 6             const str=‘我的名字是:‘+this.userName+",年龄是:"+this.age;
 7             console.log(str); 
 8         }
 9     };
10 
11     const other =user.selfIntroduction;
12     other();  //我的名字是:undefined,年龄是:undefined
13 
14     const data={
15         userName:‘小李‘,
16         age:19,
17     };
18     data.selfIntroduction=user.selfIntroduction;
19     data.selfIntroduction();  //我的名字是:小李,年龄是:19

  在看这段代码,将selfIntroduction()赋值给了全局变量other,调用other()方法,other挂载在全局函数window对象下,window对象下没有userName 和 age 这两个属性,所以输出为undefined。第二段代码,申明了data对象,包含了username和age属性,记住我们的第二条规则一般情况下this指向它的调用者,大家就明白了,data是selfIntroduction()的函数的调用者,所以输出了data的userName和age。

3:在html里作为事件触发

<body>

    <div id="btn">点击我</div>

</body>
1         const btn=document.getElementById(‘btn‘);
2 
3         btn.addEventListener(‘click‘,function () {
4             console.log(this);  //<div id="btn">点击我</div>
5         })

在种情况其实也是遵循了第二条规则一般情况下this指向它的调用者,this指向了事件的事件源即event。

4:new关键字(构造函数)

1     const  fun=function(userName){
2         this.userName=userName;
3     }
4 
5     const  user=new fun(‘郭德纲‘);    
6 
7     console.log(user.userName);  //郭德纲

 这个就不多赘述了,new关键字构造了一个对象实例,赋值给了user,所以userName就成为了user对象的属性。

5:es6(箭头函数)

1     const func1=()=>{
2 
3         console.log(this);  
4 
5     };
6 
7     func1(); //Window 
 1     const data={
 2         userName:‘校长‘,
 3         selfIntroduction:function(){
 4             console.log(this); //Object {userName: "校长", selfIntroduction: function}
 5 
 6             const func2=()=>{
 7                 console.log(this);  //Object {userName: "校长", selfIntroduction: function}
 8             }
 9 
10             func2();
11         }
12 
13     }
14 
15     data.selfIntroduction();

  大家在看看我开头说的第三条准则:es6的箭头函数中,this指向创建者,并非调用者,fun1 在全局函数下创建,所以this指向全局window,而fun2在对象data下创建,this指向data对象,所以在func2函数内部this指向data对象,个人认为es6的箭头函数的this指向是对我上面所说的javascript设计缺陷的改进,(个人认知)。

6:改变this的指向

  call、apply、bind这三个函数是可以人为的改变函数的this指向的,在这里就不多说这三者的区别了,在往后的博客里我会详细解释这三者的区别的。现在先拿一个来举一个例子

1 const func=function(){
2     console.log(this);
3 };
4 
5 func(); //window
6 
7 func.apply({userName:"郭德纲"});  //Object {userName: "郭德纲"}

   这三个方法都是可以人为的改变this的指向,区别是call、apply会将该方法绑定this之后立即执行,而bind方法会返回一个可执行的函数。

说这很多总结起来就是我开头说的4点

1:全局变量默认挂载在window对象下
2:一般情况下this指向它的调用者
3:es6的箭头函数中,this指向创建者,并非调用者
4:通过call、apply、bind可以改改变this的指向

说实话第一次写博客,确实挺忐忑的,会不会有人看我的博客?会不会写的不正确?……想好多了,总结了:不好的地方欢迎指正。

  

 

 

       

   








以上是关于javaScript的this指向总结(原创)的主要内容,如果未能解决你的问题,请参考以下文章

「思考题」54个JavaScript基础知识总结

Javascript中 this的精要总结

JavaScript语法——this

Javascript中call,apply,bind方法的详解与总结

JavaScript学习总结——this原型链javascript面向对象

JavaScript中this指向问题