理解 JavaScript 中的关键字 this”

理解 JavaScript 中的关键字“this”

原文:https://medium.com/hackernoon/get-your-head-around-this-73c23653b102

JavaScript 中的“this"关键字可能会引起混淆。我们来揭秘一下吧!

JavaScript 中,this关键字的用法与我们在普通句子中使用它的用法相同:它指的是我们之前已经介绍过的内容。

如果我说:“我昨天在一个网络大会上遇到了加里·韦纳尔查克。这家伙太厉害了。”,你马上明白“这家伙”指的是加里·韦纳尔楚克。

同样,在 JavaScript 中使用时,this指的是一个对象,更确切地说是调用代码的对象。

考虑这个例子:

自己试试

我们创建了一个带有属性的customer对象和一个greetCustomer方法。该方法使用关键字this来引用customer对象。

注意this能够访问对象的属性(firstNamelastName)。这是因为不仅 **this** 引用 **customer** 对象,而且包含对象的值:因此它可以访问对象的方法和属性。

greetCustomer方法被调用时,方法内的this自动引用调用该方法的对象:对象customer。但是在方法被调用之前,这一点非常重要,没有给*this* 赋值

这是什么意思?

以这个函数为例:

var sayCatName = function(catName){
    console.log("My cat's name is " + catName);
};

它要打印什么?嗯,目前还不多,我们已经定义了函数,但是我们不知道catName的值,直到我们调用函数并给它传递一个猫的名字:

sayCatName('Alphonse'); // Prints "My cat's name is Alphonse"

这也是关键字this背后完全相同的想法:我们不知道它指的是什么,直到一个对象调用定义了this的函数。换句话说,this关键字直到定义它的函数被实际调用时才会被赋值。

所以每当你试图弄清楚 **this** 关键字指的是什么时,问问自己这个问题:“这个函数在哪里被调用?” 。不是定义它的地方,而是调用它的地方。

每当你试图弄清楚this关键字指的是什么时,问问自己这个问题:“这个函数在哪里被调用?”。不是定义它的地方,而是调用它的地方。

这是一个基本的例子,在我们的代码中,有时更难确定this指的是什么。现在,让我们深入了解允许我们这样做的四条规则:

  • 隐式绑定(当this在声明的对象内部时)
  • 显式绑定(当我们使用callapplybind显式设置this的值时)
  • 全局上下文(当this在声明对象之外时)
  • `new`关键字(创建新对象时)

1.隐式绑定(当this在声明的对象内时)

当关键字this在声明的对象中被发现时,this的值将总是最近的父对象。

用新方法考虑我们的客户对象whatIsMyObject:

→自己试试

我们首先在函数greetCustomer中找到关键字this。最接近的父对象是customer对象,这意味着this的值是customer对象。

当我们在函数whatIsMyObject中单独打印this时,其最近的父对象也是customer对象,我们得到了控制台中打印的整个对象,所以我们现在确定this的值是customer对象。

这很好,但是当我们有一个嵌套对象时会发生什么呢?

A nested object

→自己试试

我们给名为addresscustomer对象添加了一个键。address的值是另一个对象。在这个对象中,我们有一个askAddress函数,它使用this来称呼客户的名字。

但是this似乎无法访问customer对象的属性name并打印“亲爱的未定义,请输入您的地址”。你猜到原因了吗?

让我们回到我们的规则,即this的值总是最近的父对象:这里我们在customer对象中,但也在嵌套的address对象中,当它在函数askAdress中时,它实际上是this最近的父对象。

因为address对象没有属性firstName,所以this.firstName是未定义的。我们还可以看到,address对象内部的whatIsMyObject函数不再引用customer,而是引用address

那么我们该如何解决这个问题呢?如果我们需要我们的askAddress方法返回客户的名字,该怎么办?我们需要用callapplybind方法显式地改变this的值。

2.显式绑定(当我们使用callapplybind显式设置this的值时)

JavaScript 中的函数是对象,作为对象,它们有几个方法。当我们想要完全控制关键字this所指的内容时,我们使用函数的callapplybind方法。

让我们看一下我们在前面的例子中使用的代码:

之前,我们调用的是返回“亲爱的未定义……”customer.address.askAddress,因为askAddress函数中this的值引用了address对象,而该对象没有firstName属性。

call()

通过使用call方法,我们可以改变我们想要的this的值:这里我们将把this的值改为customer对象:

customer.address.askAddress.call(customer); // Prints "Dear John, please enter your address"

→自己试试

成功了!注意,我们不是调用 askAddress,我们只是将方法call附加到上,所以当我们使用call时在askAddress方法后面没有括号。

call方法的参数是我们希望关键字this引用的,在本例中是customer对象。

apply()

当我们对想要使用callapply的函数有参数时,就可以看出callapply的区别。

我们创建了一个新方法calculateAge,它有两个参数currentYearbirthDate

自己试试

两种解决方案都有效,唯一的区别是:

  • 使用call函数,我们传递由逗号分隔的参数,
  • 使用apply函数,我们将参数作为数组中的值传递

bind()

bind的工作方式与call类似,但是并没有立即调用函数,而是返回一个函数定义,将this设置为传递给bind()的第一个参数。

→自己试试

bind允许我们明确地将this设置为我们想要的对象。它生成一个我们存储在变量ageOfCustomer3中的calculateAge函数的副本,但是它不会立即调用函数。

我们可以稍后在代码中调用该函数,并传递它需要执行的参数。创建带有预置参数的函数是非常有用的,这些函数将在以后被调用,而this已经被设置为正确的对象。

3.全局上下文(当this在声明的对象之外时)

this是在全局上下文中,当你发现它“在野外”,在一个声明的对象之外(意味着没有一个包含关键字this的对象被定义)。

在这种情况下,它的值引用全局对象,在浏览器中,它对应于window对象。

事实上,在全局范围内声明的每个变量实际上都附加到了窗口对象上:

→自己试试

如果我们发现this在一个常规的函数调用里面(不是一个对象或者一个对象的方法)怎么办?在这种情况下,this关键字也指向全局对象。

→自己试试

这里当我调用greetCustomer方法时,nestedFunction将被调用,并打印全局窗口对象,即使我们在customer对象内部。这是为什么呢?

这里我们有一个方法内部的常规函数调用,而不是对象的方法。虽然它写在方法内部,但它仍然是一个简单的函数。

4.new关键字

创建对象的一种方法是使用new关键字。

考虑定义一个对象的函数 Customer:

function Customer(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

在这个函数中,我们用关键字this定义对象的属性,它们将等于传递给函数的值。

等等,我们在一个函数里面。正如我们前面看到的,this的值不应该是全局对象吗?

但是在这种情况下,我们不会进行常规的函数调用来创建一个新对象。相反,我们将使用new关键字,规则是当您使用new关键字时,this的值会改变。

var customer1 = new Customer("John", "Smith");console.log(customer1.firstName + " " + customer1.lastName); // Prints "John Smith"

→自己试试

this现在指的是使用new关键字时创建的对象。我们将该对象存储在一个名为customer1的变量中,该变量现在可以访问firstNamelastName属性。

结论

要知道代码中this的值是多少,总是要问自己这样一个问题:

在哪里调用函数?

this有一些非常棘手的部分,在本文中有详细介绍:

当我们借用一个使用this的方法时,当我们将一个使用this的方法赋给一个变量时,当一个使用this的函数作为回调函数被传递时,当this被用在一个闭包——一个内部函数中时,this关键字最容易被误解

在使用原生 JavaScript 或 jQuery 之类的库时,您肯定会经常遇到一些现实世界中的问题,在这些情况下,理解this的基本工作原理会有很大的帮助。

想了解更多?查看我关于 JavaScript 基础的其他文章:

我希望你喜欢这篇关于 JavaScript 关键字“this”的介绍。

请随意评论并喜欢这篇文章,以便其他人可以在 Medium 上轻松找到它!

****

黑客中午是黑客如何开始他们的下午。我们是 T21 家庭的一员。我们现在接受投稿并乐意讨论广告&赞助机会。

如果你喜欢这个故事,我们推荐你阅读我们的最新科技故事趋势科技故事。直到下一次,不要把世界的现实想当然!


本站为非盈利网站,作品由网友提供上传,如无意中有侵犯您的版权,请联系删除