关于JavaScript中的this指向问题总结篇


Posted in Javascript onJuly 23, 2017

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

1:全局变量默认挂载在window对象下

2:一般情况下this指向它的调用者

3:es6的箭头函数中,this指向创建者,并非调用者

4:通过call、apply、bind可以改改变this的指向

下面我们具体分析一下

1:在函数调用时

(非严格模式)

const func = function () {
    console.log(this);
    const func2 = function () {
      console.log(this);
    };
    func2(); //Window
  };
  func(); //Window

 

(严格模式)

'use strict'
  const func = function () {
    console.log(this);
    const func2 = function () {
      console.log(this);
    };
    func2(); //undefined
  };
  func(); //undefined

 

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

2:作为对象方法

const user = {

    userName: '小张',
    age: 18,
    selfIntroduction: function () {
      const str = '我的名字是:' + this.userName + ",年龄是:" + this.age;
      console.log(str);

      const loop = function () {
        console.log('我的名字是:' + this.userName + ",年龄是:" + this.age);
      };

      loop();   //我的名字是:undefined,年龄是:undefined

    }
  };

  user.selfIntroduction();  //我的名字是:小张,年龄是:18

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

const user = {
    userName: '小张',
    age: 18,
    selfIntroduction: function () {
      const str = '我的名字是:' + this.userName + ",年龄是:" + this.age;
      console.log(str);

      const that=this;

      const loop = function () {
        console.log('我的名字是:' + that.userName + ",年龄是:" + that.age);
      };

      loop();   //我的名字是:小张,年龄是:18

    }
  };

  user.selfIntroduction();  //我的名字是:小张,年龄是:18

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

const user={

    userName:'小张',
    age:18,
    selfIntroduction:function(){
      const str='我的名字是:'+this.userName+",年龄是:"+this.age;
      console.log(str); 
    }
  };

  const other =user.selfIntroduction;
  other(); //我的名字是:undefined,年龄是:undefined

  const data={
    userName:'小李',
    age:19,
  };
  data.selfIntroduction=user.selfIntroduction;
  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>
     const btn=document.getElementById('btn');
    btn.addEventListener('click',function () {
      console.log(this); //<div id="btn">点击我</div>
    })

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

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

const fun=function(userName){
    this.userName=userName;
  }
  const user=new fun('郭德纲');  
  console.log(user.userName); //郭德纲

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

5:es6(箭头函数)

const func1=()=>{
    console.log(this); 
  };
  func1(); //Window
const data={
    userName:'校长',
    selfIntroduction:function(){
      console.log(this); //Object {userName: "校长", selfIntroduction: function}
      const func2=()=>{
        console.log(this); //Object {userName: "校长", selfIntroduction: function}
      }

      func2();
    }
  }
  data.selfIntroduction();

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

6:改变this的指向

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

const func=function(){
   console.log(this);
 }; 
 func(); //window
 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指向问题总结篇,希望对大家有所帮助,如果大家有任何问题,欢迎给我留言,小编会及时回复大家的!

Javascript 相关文章推荐
Javascript中的常见排序算法
Mar 27 Javascript
javascript去掉前后空格的实例
Nov 07 Javascript
jQuery中获取checkbox选中项等操作及注意事项
Nov 24 Javascript
浅析AMD CMD CommonJS规范--javascript模块化加载学习心得总结
Mar 16 Javascript
JS中的==运算: [''] == false —&gt;true
Jul 24 Javascript
JS去掉字符串前后空格、阻止表单提交的实现代码
Jun 08 Javascript
JavaScript学习总结之正则的元字符和一些简单的应用
Jun 30 Javascript
ES7中利用Await减少回调嵌套的方法详解
Nov 01 Javascript
JS实现二维数组横纵列转置的方法
Apr 17 Javascript
对layui中表单元素的使用详解
Aug 15 Javascript
layui之table checkbox初始化时选中对应选项的方法
Sep 02 Javascript
vue-cli或vue项目利用HBuilder打包成移动端app操作
Jul 29 Javascript
浅析JS中常用类型转换及运算符表达式
Jul 23 #Javascript
js实现带进度条提示的多视频上传功能
Dec 13 #Javascript
基于javaScript的this指向总结
Jul 22 #Javascript
JavaScript之事件委托实例(附原生js和jQuery代码)
Jul 22 #jQuery
基于LayUI实现前端分页功能的方法
Jul 22 #Javascript
浅谈原型对象的常用开发模式
Jul 22 #Javascript
浅谈事件冒泡、事件委托、jQuery元素节点操作、滚轮事件与函数节流
Jul 22 #jQuery
You might like
php checkdate、getdate等日期时间函数操作详解
2010/03/11 PHP
PHP生成Flash动画的实现代码
2010/03/12 PHP
强制PHP命令行脚本单进程运行的方法
2014/04/15 PHP
PHP生成指定随机字符串的简单实现方法
2015/04/01 PHP
PHP引用返回用法示例
2016/05/28 PHP
thinkPHP简单导入和使用阿里云OSSsdk的方法
2017/03/15 PHP
老生常谈php中传统验证与thinkphp框架(必看篇)
2017/06/10 PHP
pjblog中的UBBCode.js
2007/04/25 Javascript
很可爱的输入框
2008/08/03 Javascript
js 刷新页面的代码小结 推荐
2010/04/02 Javascript
javascript是怎么继承的介绍
2012/01/05 Javascript
jquery设置元素的readonly和disabled的写法
2013/09/22 Javascript
Javascript实现页面跳转的几种方式分享
2013/10/26 Javascript
点击显示指定元素隐藏其他同辈元素的方法
2014/02/19 Javascript
js父窗口关闭时子窗口随之关闭完美解决方案
2014/04/29 Javascript
JavaScript移除数组内重复元素的方法
2015/03/18 Javascript
jQuery实现拖拽效果插件的方法
2015/03/23 Javascript
nodejs实现HTTPS发起POST请求
2015/04/23 NodeJs
纯javascript实现分页(两种方法)
2015/08/26 Javascript
jQuery Mobile页面返回不需要重新get
2016/04/26 Javascript
使用ionic(选项卡栏tab) icon(图标) ionic上拉菜单(ActionSheet) 实现通讯录界面切换实例代码
2017/10/20 Javascript
Vue中的异步组件函数实现代码
2018/07/20 Javascript
vue构建动态表单的方法示例
2018/09/22 Javascript
Vue中computed、methods与watch的区别总结
2019/04/10 Javascript
[57:18]DOTA2上海特级锦标赛主赛事日 - 1 败者组第一轮#3VP VS VG
2016/03/03 DOTA
[53:44]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Magma BO3 第一场 1月31日
2021/03/11 DOTA
Python守护进程用法实例分析
2015/06/04 Python
python实现八大排序算法(1)
2017/09/14 Python
python实现在cmd窗口显示彩色文字
2019/06/24 Python
Python协程 yield与协程greenlet简单用法示例
2019/11/22 Python
python双端队列原理、实现与使用方法分析
2019/11/27 Python
Python requests设置代理的方法步骤
2020/02/23 Python
详解python定时简单爬取网页新闻存入数据库并发送邮件
2020/11/27 Python
初中生三年学习生活的自我评价
2013/11/03 职场文书
职业女性的职业规划
2014/03/04 职场文书
服装设计专业毕业生求职信
2014/04/09 职场文书