理解 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能够访问对象的属性(firstName和lastName)。这是因为不仅 **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在声明的对象内部时) - 显式绑定(当我们使用
call、apply或bind显式设置this的值时) - 全局上下文(当
this在声明对象之外时) - `new`关键字(创建新对象时)
1.隐式绑定(当this在声明的对象内时)
当关键字this在声明的对象中被发现时,this的值将总是最近的父对象。
用新方法考虑我们的客户对象whatIsMyObject:
我们首先在函数greetCustomer中找到关键字this。最接近的父对象是customer对象,这意味着this的值是customer对象。
当我们在函数whatIsMyObject中单独打印this时,其最近的父对象也是customer对象,我们得到了控制台中打印的整个对象,所以我们现在确定this的值是customer对象。
这很好,但是当我们有一个嵌套对象时会发生什么呢?
A nested object
我们给名为address的customer对象添加了一个键。address的值是另一个对象。在这个对象中,我们有一个askAddress函数,它使用this来称呼客户的名字。
但是this似乎无法访问customer对象的属性name并打印“亲爱的未定义,请输入您的地址”。你猜到原因了吗?
让我们回到我们的规则,即this的值总是最近的父对象:这里我们在customer对象中,但也在嵌套的address对象中,当它在函数askAdress中时,它实际上是this最近的父对象。
因为address对象没有属性firstName,所以this.firstName是未定义的。我们还可以看到,address对象内部的whatIsMyObject函数不再引用customer,而是引用address。
那么我们该如何解决这个问题呢?如果我们需要我们的askAddress方法返回客户的名字,该怎么办?我们需要用call、apply或bind方法显式地改变this的值。
2.显式绑定(当我们使用call、apply或bind显式设置this的值时)
JavaScript 中的函数是对象,作为对象,它们有几个方法。当我们想要完全控制关键字this所指的内容时,我们使用函数的call、apply和bind方法。
让我们看一下我们在前面的例子中使用的代码:
之前,我们调用的是返回“亲爱的未定义……”的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()
当我们对想要使用call或apply的函数有参数时,就可以看出call和apply的区别。
我们创建了一个新方法calculateAge,它有两个参数currentYear和birthDate。
→ 自己试试
两种解决方案都有效,唯一的区别是:
- 使用
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的变量中,该变量现在可以访问firstName和lastName属性。
结论
要知道代码中this的值是多少,总是要问自己这样一个问题:
在哪里调用函数?
this有一些非常棘手的部分,在本文中有详细介绍:
当我们借用一个使用
this的方法时,当我们将一个使用this的方法赋给一个变量时,当一个使用this的函数作为回调函数被传递时,当this被用在一个闭包——一个内部函数中时,this关键字最容易被误解
在使用原生 JavaScript 或 jQuery 之类的库时,您肯定会经常遇到一些现实世界中的问题,在这些情况下,理解this的基本工作原理会有很大的帮助。
想了解更多?查看我关于 JavaScript 基础的其他文章:
- [JavaScript 中的吊装:快速指南](https://hackernoon.com/hoisting-in-javascript-a-quick-guide-cc4d9597bbd7)
- [轻松理解 JavaScript 变量作用域](https://hackernoon.com/understand-javascript-variable-scope-with-ease-221a6d41dc43)
- [如何放心使用 JavaScript 闭包](/@lenafaure/how-to-use-javascript-closures-with-confidence-85cd1f841a6b)
- [掌握 JavaScript](https://hackernoon.com/grasp-by-value-and-by-reference-in-javascript-7ed75efa1293) 中的“按值”和“按引用”
- [JavaScript 中的日期快速手册](https://hackernoon.com/a-quick-handbook-for-dates-in-javascript-7b71d0ef8e53)
- [像老板一样使用 JavaScript 数组](/@lenafaure/work-with-javascript-arrays-like-a-boss-97207a042e42)
我希望你喜欢这篇关于 JavaScript 关键字“this”的介绍。
请随意评论并喜欢这篇文章,以便其他人可以在 Medium 上轻松找到它!




