📜  JavaScript 中的 this

📅  最后修改于: 2022-05-13 01:56:44.946000             🧑  作者: Mango

JavaScript 中的 this

JavaScript 中的this关键字通常是该语言初学者的困惑之源。这种混淆部分源于这样一个事实,即 JavaScript 中的this与其他语言(如Java或Python中的 self )的处理方式不同。
为了理解 JavaScript 中更高级的概念或读写 JavaScript 代码,理解这一点是绝对必要的,这就是为什么我们将在本文中试图阐明这在 JavaScript 中的真正含义。
我们将在本文的大部分时间里参考 JavaScript 中的函数来学习方面的知识,这就是为什么我们首先要了解一个关于 JavaScript 函数的事实,它可以帮助我们更好地做到这一点。

this 和函数

JavaScript 中的函数本质上是对象。像对象一样,它们可以分配给变量,传递给其他函数并从函数返回。就像对象一样,它们也有自己的属性。这些属性之一是this
this存储的值是 JavaScript 程序的当前执行上下文。因此,当在函数内部使用时, this的值将根据该函数的定义方式、调用方式和默认执行上下文而改变。
注意:始终包含对单个对象的引用,该对象定义了当前代码行的执行上下文。
在我们深入研究 this 在函数中的行为之前,让我们看看它在函数之外的行为:
全球背景:
写在函数外部的一行代码被称为属于全局上下文,并且在这个全局上下文中 this 的值与全局对象相同。
例如,如果您打开浏览器控制台并在其中输入以下行,然后按回车键/回车键:
控制台日志(这个)
您会看到 Window 对象被登录到控制台。这是因为在浏览器运行时(例如 Chrome 的运行时)中的全局对象是 Window 对象。
然而,在函数内部,全局上下文可能不再存在,函数可能有自己定义的上下文,因此 this 的值不同。为了理解这一点,让我们将注意力转回函数:
JavaScript 中的函数可以通过多种方式调用:
1.函数调用
2.方法调用
3.构造函数调用

这与函数调用:

函数调用是指使用函数的名称或表达式调用函数的过程,该表达式计算为函数对象,后跟一组打开和关闭的第一个括号(包含括号表示我们正在要求 JavaScript 引擎立即执行该函数)。
例如:

JavaScript



                    



JavaScript



                    



JavaScript



                    



JavaScript



                    



JavaScript



                    



JavaScript



                 



JavaScript



                    



JavaScript



         



doSomething函数里面的this ,如果通过上面的函数调用来调用的话,它的值就是全局对象,也就是浏览器环境中的window对象:

JavaScript




                    

                        

输出:

test value 

然而,这并非总是如此。如果 doSomething()函数在严格模式下运行,它将记录undefined而不是全局窗口对象。这是因为,在严格模式下(由行 : 'use strict';表示), this 的默认值,对于任何函数对象都设置为未定义而不是全局对象。
例如 :

JavaScript




                    

                                           

输出:

undefined
undefined 

这与方法调用:

函数,当定义为对象的字段或属性时,称为方法。

JavaScript




                    

                                        

输出:

John is 31 years old 

在上面的代码示例中, logInfo()person 对象的一个方法,我们使用对象调用模式来调用它。
也就是说,我们使用属性访问器来访问作为对象一部分的方法。
这样的调用需要使用一个表达式来计算我们的方法所属的对象,以及一个属性访问器(例如: person.logInfo() ),后跟一组左括号和右括号。
了解函数调用和方法调用的不同之处至关重要。
这反过来将帮助我们理解this上下文在任何给定函数中可能是什么,因为在每个调用中, this的值都是不同的。
在使用属性访问器调用的此类方法中, this将具有调用对象的值,即this将指向与属性访问器一起使用以进行调用的对象。
例如 :

JavaScript




                    


输出:

[object Object] 1
[object Object] 2 

在上面的示例中,calc() 是 add 对象的方法,因此使用第 9 行和第 10 行中的方法调用规则进行调用。
我们知道,当使用方法调用模式时, this的值被设置为调用对象。
在这个 calc() 方法中,this 的值被设置为调用对象,在我们的例子中是 add。因此我们可以成功访问 add 的 num 属性。
但是,让我们看看一个主要的混淆点:
在嵌套在对象方法中的函数中会发生什么

JavaScript




                 

                               

输出:

[object Object] [object Window] NaN
[object Object] [object Window] NaN 

让我们试着理解刚刚发生的事情。
当我们在第 14 行和第 15 行调用 calc() 时,我们正在使用方法调用,它将this设置为添加到 calc() 中。这可以使用第 4 行中的 log 语句来验证。
但是,使用简单的函数调用(第 11 行)从 calc() 方法中调用 innerfunc()。这意味着,在 innerfunc() 内部,this 被设置为没有 num 属性的全局对象,因此获得了 NaN 输出。
我们如何解决这个问题?我们如何从嵌套函数内部的外部方法中保留 this 的值?
一种解决方案是将外部函数的this值分配给要在嵌套函数中使用的变量,如下所示:

JavaScript




                    

                                                

输出:

[object Object] [object Object] 1
[object Object] [object Object] 2 

此问题的其他解决方案包括使用 bind()、call() 或 apply(),我们将很快研究这些方法。

this 与构造函数调用:

当 new 关键字后跟一个函数名和一组左括号和右括号(带或不带参数)时,将执行构造函数调用。
例如: let person1= new People('John', 21);
这里,person1 是新创建的对象,People 是用于创建该对象的构造函数。
构造函数调用是在 JavaScript 中创建对象的几种方法之一。
当我们将 new 关键字与函数名结合使用时,究竟会发生什么?
通过这种方法创建对象基本上涉及五个步骤。让我们用下面的例子来研究它们:

JavaScript




         

                                                                                   

输出:

John is 21 years old 
  • 首先,创建一个空对象,它是与 new 一起使用的函数名称的实例(即:people(name, age))。换句话说,它将对象的构造函数属性设置为调用中使用的函数(people(name, age))。
  • 然后,它将构造函数的原型(人)链接到新创建的对象上,从而保证这个对象可以继承构造函数的所有属性和方法
  • 然后,在这个新创建的对象上调用构造函数。如果我们回想方法调用,我们会发现是相似的。因此,在构造函数内部, this获取调用中使用的新创建对象的值。
  • 最后,将创建的对象及其所有属性和方法集返回给 person1

支持的浏览器:

  • 谷歌浏览器
  • 微软边缘
  • 火狐
  • 歌剧
  • 苹果浏览器