JavaScript】js中this指向详解

2020-12-18 20:00发布

8条回答
听雨
2楼 · 2020-12-18 21:04

总结起来说就是4点

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

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

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

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


孙哈哈
3楼 · 2020-12-18 23:10

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象

this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的

普通函数中的this指向:

1.如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window

2.如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。

3.如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象


Kindery
4楼 · 2020-12-19 10:54

1.如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,这里需要说明的是在js的严格版中this指向的不是window,但是我们这里不探讨严格版的问题,你想了解可以自行...

2.如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。

3.如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用...


梵梵
5楼 · 2020-12-19 15:09

在绝大数情况下,函数的调用方式决定了this值。this不能在执行期间被复制,并且在每次函数被调用时this的值也可能会不同。

this的值表示当前执行的环境对象,而与声明环境无关,所以this代表的对象要等函数运行。类似定义函数时的参数列表,只有在函数调用时才传入真正的对象。

this关键字虽然会根据环境变化,但它始终代表的是调用当前函数的对象。


我的网名不再改
6楼 · 2020-12-19 19:06

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


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

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

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

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

下面我们具体分析一下

1:在函数调用时

  (非严格模式)

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

  (严格模式)

1
2
3
4
5
6
7
8
9
'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:作为对象方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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缓存下来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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指向就理想了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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里作为事件触发

1
2
3
4
5
6
7
   

 "btn" >点击我

      const btn=document.getElementById( 'btn' );
     btn.addEventListener( 'click' , function  () {
       console.log( this );  //

点击我

     })

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

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


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

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

5:es6(箭头函数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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指向的,在这里就不多说这三者的区别了,在往后的博客里我会详细解释这三者的区别的。现在先拿一个来举一个例子

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

  这三个方法都是可以人为的改变this的指向,区别是call、apply会将该方法绑定this之后立即执行,而bind方法会返回一个可执行的函数。apply与call的用法是一致的,只是传参形式上call我们是这样的xxx.call(obj, arg1, arg2,...),而apply的参数必须要以数组的形式传递xxx.apply(obj, ['arg1', 'arg2', ...]),

bind是以call的形式传参的,但是bind与call、apply最大的区别就是bind绑定this指向并传参后仍然为一个函数,并没有去调用,而call与apply是直接调用函数。

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

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

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

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

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


py大白
7楼 · 2020-12-25 12:36

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象

this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的

普通函数中的this指向:

1.如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window

2.如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。

3.如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象


summermo
8楼 · 2021-01-26 10:34

总的来说,this指向就是谁调用了函数,this就默认指向谁,在哪个环境下的函数,就指向哪个环境下的对象


全局函数中this指向window对象


字面量对象中的this指向当前字面量对象本身


构造函数对象中的this指向构造函数对象本身


事件函数对象中的this指向当前事件类型前面的那个事件对象


当然也可以使用call、apply两个方法修改this的默认指向

Sauvignon
9楼 · 2021-01-27 13:55

this是一个特殊的全局对象,在不同的环境中代表不同的含义,

在普通命名函数中,this指向window;

在对象中的函数,this指向该对象;

在事件驱动函数中,this指向触发事件的对象;

在构造函数中,this指向当前的实例对象;

相关问题推荐

  • 回答 8

    向一个对象数组里面添加新的属性var arry= [{a:11,b:22,c:33,d:44},{a:11,b:0,c:0,d:44},{a:11,b:22,c:99,d:99}];var arry2=[];arry.map(((item, index)=> {arry2.push(Object.assign({},item,{mess1:item.c,mess2:item.d}))}))cons...

  • 回答 2

    我觉得getTopWindow() 应该是他自己写的函数 mask  应该是getTopWindow()函数中 return 出的一个什么玩意show()  jQuery的显示

  • 回答 9

    如图所示

  • 回答 12

    1、原型对象也是普通的对象,是对象一个自带隐式的 __proto__ 属性,原型也有可能有自己的原型,如果一个原型对象的原型不为 null 的话,我们就称之为原型链 2、 原型链是由一些用来继承和共享属性的对象组成的(有限的)对象链...

  • 回答 6

    使用VS code对JS进行Debug,需要安装一个插件,这个插件是根据你所使用的浏览器来的,不同浏览器对应插件不同,以下是插件对应情况,下载完相应的插件以后还要下载一个live server在浏览器下查看你界面运行效果,记得在到设置里修改下live server的端口号,然...

  • 回答 8
    已采纳

    没有基础,是可以学Java的,在网上也能找到很多免费的视频、学习资料等资源,只不过想要光靠自己摸索学透Java并不容易,最好是找一个比较靠谱的有实训的培训机构。不过,我给你点建议:1.脑子里要有编程思维,2.学习态度要有,3.了解了基本概念后,从图形界面...

  • 回答 7

    假设文本框的id=text1js:document.getElementById(text1).value = 测试;//即可

  • 回答 2

    这两个事件都是在js原生开发时经常会用到的,比如需要对页面dom进行动态处理,这时就需要用到DOMContentLoaded和[removed]事件,大家都知道,就是在dom构建完毕后,才可以对dom元素进行操作,否则会获取不到相应的dom元素,但是DOMContentLoaded和[removed]还...

  • 回答 11

    基本概念CookieCookie 是小甜饼的意思。顾名思义,cookie 确实非常小,它的大小限制为4KB左右。它的主要用途有保存登录信息,比如你登录某个网站市场可以看到记住密码,这通常就是通过在 Cookie 中存入一段辨别用户身份的数据来实现的。localStoragelocalStor...

  • 回答 2

    在vscode 头疼的问题是 用浏览器查看网页!会是以文件夹的方式打开的!  我遇到这个问题 我还重新配置了Apache    ! 但是现在可以解决:使用vscode  ==================== 打开cmd   : 在cmd 控制台中输入  :   1.运行cnpm install live-server...

  • 回答 1

    在进行对象之间的合并的时候,就会使用到extend方法进行合并语法结构:$.extend(true,{},对象1,对象2...)但是这里需要考虑一个问题,如果对象间有相同的属性名,就会涉及到哪一个对象和哪一个对象的值覆盖合并的问题,如果对象中的属性值还是一个对象的话,那...

  • 回答 5
    已采纳

    先说下要实现什么功能,比如:限制图片大小不能超过30K,宽高为121x75上面需求提了,然后我直接把代码给你放出来,可以照着下面代码敲一遍试试就知道怎么限制图片宽高了 $(#picFile4).on(change,function(){ var imgFile = this.files[0]; va...

  • 回答 3

    用python爬取近30天百度指数代码均转载,如下:#1.登录url = ‘http://index.baidu.com/’driver = webdriver.Chrome(executable_path=‘C:/Program Files(x86)/Google/Chrome/Application/chromedriver.exe’)driver.get(url)cookieList = [......

  • 回答 7

    基本类型基本类型分为以下六种:string(字符串)boolean(布尔值)number(数字)symbol(符号)null(空值)undefined(未定义)注意:string 、number 、boolean 和 null  undefined 这五种类型统称为原始类型(Primitive),表示不能再细分下去的基本类...

  • 回答 11

    实体类中添加时间转换注解(注意时区问题)12345/**  * 开始时间  */ @JsonFormat(pattern = yyyy-MM-dd HH:mm:ss, timezone=GMT+8) private Date startTime;

  • 回答 5

    实例中包含加、减、乘、除四种运算,由于先乘和除的优先级别高,所以乘和除将首先被运算,接下来是加和减运算。乘和除优先级相同,所以左边的乘法将被先执行,然后是除法,接下来按从左到右的顺序进行加减运算...

没有解决我的问题,去提问