JavaScript的“ this”通过成立一个高中乐队来解释

news/2024/7/5 2:33:58

by Kevin Kononenko

凯文·科诺年科(Kevin Kononenko)

JavaScript的“ this”通过成立一个高中乐队来解释 (JavaScript’s “this” Explained By Starting A High School Band)

If you have ever been in a band, had a friend that started a band, or seen a corny 80s movie about starting a band, then you can understand the concept of “this” in JavaScript.

如果您曾经参加过乐队,或者有朋友开始过乐队,或者看过关于80年代老套的电影,那么您可以理解JavaScript中“ this”的概念。

When you are reading over some JavaScript, and you come across the this keyword, the steps you need to take in order to figure out its value might seem obvious.

当您阅读一些JavaScript时,遇到了this关键字,为了弄清它的值而需要采取的步骤似乎很明显。

You might be thinking, “I just need to find the function that contains this, and then I will know what it is referring to!”

您可能会想:“我只需要找到包含this的函数,然后我就知道它指的是什么!”

let band= {  name: "myBand",  playGig:function() {    console.log("Please welcome to the stage" + this.name);  }}

In the example above, for example, this.name refers to the name “myBand”. This seems easy!

例如,在上面的示例中, this.name引用名称“ myBand”。 这似乎很简单!

But, as you learn more JavaScript concepts, like closures and callbacks, you will quickly find that this does not behave like you would expect.

但是,当你学习更多JavaScript概念,如封锁和回调,你很快就会发现, 不会表现得像你所期望的。

So, I wanted to create a visual explanation of how this works in JavaScript. Here’s the scenario: You are back in high school, and starting a band with your friends (or maybe you are currently in high school?)

所以,我想创造的是如何工作JavaScript的可视化解释。 情况是这样的:您回到了高中,然后和您的朋友一起开始了乐队演出(或者您可能正在上高中?)

  • Your band has four members

    您的乐队有四名成员
  • You play three types of gigs: you play at bars, school competitions, and public events in town.

    您会演奏三种类型的演奏:在酒吧,学校比赛和镇上的公共活动中玩。
  • Your team can play all types of music, so you try to choose the right songs to match the audience. You don’t want curse words or sexual references at the family-friendly events, for example.

    您的团队可以播放所有类型的音乐,因此您尝试选择合适的歌曲以匹配听众。 例如,您不希望在家庭友善活动中骂人或性提及他人。

As you will soon see, the biggest concept you need to understand with this is execution context. That is what determines the value of this.

正如你很快就会看到,你需要方面的了解最大的概念是执行上下文。 那就是决定this的价值的原因

Before you use this tutorial, you need to understand objects and variables. Check out my tutorials on each of these subjects if you need to review.

在使用本教程之前,您需要了解对象和变量 。 如果需要复习,请查看我关于这些主题的教程。

If you are interested in a more technical version of this tutorial, check out the guide from JavaScriptIsSexy.

如果您对本教程的更多技术版本感兴趣,请查看JavaScriptIsSexy的指南 。

全局执行上下文 (The Global Execution Context)

Let’s say that your band needs to do a family-friendly gig at the local park as part of a local fair. You need to choose the right type of music that will keep parents happy and also not offend anyone else.

假设您的乐队需要在当地公园做家庭友好的演出,这是当地集市的一部分。 您需要选择正确的音乐类型,使父母保持快乐,同时又不会冒犯其他任何人。

Let’s say that you choose to play some songs by Billy Joel (a famous American artist), and even though this is not your favorite, you know that it’s what you need to do to get paid.

假设您选择播放比利·乔尔 ( Billy Joel,美国著名艺术家)的一些歌曲,即使这不是您的最爱,您也知道要获得报酬才需要这样做。

Here is what that looks like in code.

这就是代码中的样子。

//The songs you will play var artist= "Billy Joel";
function playGig(){   //instruments that your band will use   let instruments= ["piano", "microphone", "acousticGuitar", "harmonica"];
console.log("We are going to be playing music from " + this.artist + "tonight!"); }
playGig();

In the example above, we have an artist variable that indicates what type of music we will be playing. And we have an array full of instruments that will be used to play that music within the playGig function.

在上面的示例中,我们有一个artist 变量 ,该变量指示我们将播放的音乐类型。 我们有各种各样的乐器 ,可用于在playGig 函数中播放音乐。

In the last line, we call the playGig function. So what is this.artist, in this case?

在最后一行,我们调用playGig函数。 那么,在这种情况下, this.artist是什么?

Well, first we must determine the execution context for this function. The execution context is determined by the object that the function is called upon.

好吧,首先我们必须确定该函数的执行上下文 。 执行上下文由调用函数对象确定。

In this case, there is no object listed, so that means that the function is called on the window object. It could also be called like this:

在这种情况下,没有列出对象,这意味着在窗口对象上调用了该函数。 也可以这样称呼:

window.playGig(); "We are going to be playing music from Billy Joel tonight!"

This is the global execution context. The function is called at the level of the global object, window. And, the variable artist is available as a property of the window object (see this note on the JavaScript specification).

这是全局执行上下文 。 该函数在全局对象window级别调用。 并且,变量artist窗口对象的属性( 请参见JavaScript规范上的此注释 )。

So, in line 1 of the snippet above, we are also saying:

因此,在上面的代码段的第一行中,我们还说:

//old version- let artist = "Billy Joel"; this.artist="Billy Joel";

Your band is executing the gig on the global context by playing music that appeals to everyone (unless there are any Billy Joel haters out there).

您的乐队正在通过播放吸引所有人的音乐在全球范围内进行演出(除非那里有Billy Joel讨厌的人)。

对象级执行上下文 (Object-Level Execution Context)

Let’s say that your band got a gig at a local bar. This is great! Now, you don’t need to play music that satisfies everyone in town. You only need to play music that people can dance to.

假设您的乐队在当地一家酒吧演出。 这很棒! 现在,您无需播放满足城镇所有人需求的音乐。 您只需要播放人们可以跳舞的音乐。

Let’s say that you choose Coldplay, since most of their recent songs are pop music. You need a piano, microphone, drum set, and guitar for this gig.

假设您选择Coldplay ,因为它们的大多数最新歌曲都是流行音乐。 您需要钢琴,麦克风,架子鼓和吉他来进行演出。

Let’s create a bar object with the same pattern as we created for the public park gig.

让我们创建一个与为公园演出创建的图案相同的酒吧对象。

//The songs you will play in the public park/fair var artist= "Billy Joel";
function playGig(){   //instruments that your band will use   let instruments= ["piano", "microphone", "acousticGuitar", "harmonica"];   console.log("We are going to be playing music from " + this.artist + "tonight!"); }
//NEW PART let bar = {  artist:"coldplay",  playGig: function(){     //instruments that your band will use     let instruments= ["piano", "microphone", "guitar", "drumset"];         console.log("We are going to be playing music from " + this.artist + "tonight!");    } }

Here is the diagram for the code above:

这是上面的代码图:

So, let’s say that we want to write the code to get the gig at the bar started. We need to watch our execution context, which is the bar object in this case. Here is what that would look like:

因此,假设我们要编写代码以开始演奏会。 我们需要注意执行上下文 ,在这种情况 ,它是bar对象。 看起来像这样:

bar.playGig(); //"We are going to be playing music from coldplay tonight!"

And, we can still execute the playGig function on a global level — but we will get a different output. This is great news, since we do not want to be playing Billy Joel or Coldplay at the wrong venue…

而且,我们仍然可以在全局级别执行playGig函数-但我们将获得不同的输出。 这是个好消息,因为我们不想在错误的场地上玩比利·乔尔或酷玩乐队…

playGig(); //"We are going to be playing music from Billy Joel tonight!"

So far, this has been the easy stuff. Whenever we have been calling a function, the object that provides the execution context has been pretty straightforward. But that is about to change as we get more complex.

到目前为止,这一直很简单。 每当我们调用一个函数时,提供执行上下文的对象就非常简单。 但是随着我们变得越来越复杂,这将改变。

使用jQuery更改执行上下文 (Changing Execution Context using jQuery)

It’s the big event that has been covered in every single movie from the 1980s: The Battle of The Bands! Yes, every band in your high school is going to get into a competition to see who is the best.

这是1980年代的每部电影都涵盖的重大事件:乐队之战! 是的,您高中的每个乐队都将参加比赛,看看谁是最好的。

You are going to play some songs from AC/DC, pretty much the coolest band on the planet. But in order to do that, you need a different instrument mix than before:

您将要播放AC / DC上的一些歌曲,这几乎是地球上最酷的乐队。 但是为了做到这一点,您需要与以前不同的乐器组合:

  • A microphone

    麦克风
  • An electric guitar

    电吉他
  • A bass guitar

    低音吉他
  • A drumset

    架子鼓

Let’s call this the battle object. Here is what it looks like in code.

我们称其为战斗对象 。 这就是代码中的样子。

let battle = {  artist:"acdc",  playGig: function(){     //instruments that your band will use     let instruments= ["microphone", "electricguitar", "bass", "drumset"];
console.log("We are going to be playing music from " + this.artist + "tonight!");   } }

Since this is an annual event, we are going to use a click event from jQuery to start your show. Here is what that looks like:

由于这是一项年度活动,因此我们将使用jQuery的click 事件来开始您的表演。 看起来像这样:

$('#annualBattle').click(battle.playGig);

But if you actually ran this code… it would not work. Your band would forget the words and the notes, then slowly walk off the stage.

但是,如果您实际上运行了此代码,它将无法正常工作。 您的乐队会忘记单词和音符,然后慢慢离开舞台。

To figure out why, let’s return to execution context. We are referencing a DOM element called #annualBattle, so let’s see where that fits within the window object.

为了弄清楚原因,让我们回到执行上下文。 我们正在引用一个名为#annualBattle的DOM元素,所以让我们看一下它在window对象中的适合位置。

Since #annualBattle is an element in the DOM, it is part of the document object within the window object. It doesn’t have any property called artist. So if you ran the code, you would get:

由于#annualBattle是DOM中的元素,因此它是window对象内文档对象的一部分。 它没有任何称为artist的属性。 因此,如果运行代码,您将获得:

$('#annualBattle').click(battle.playGig); //"We are going to be playing music from undefined tonight!"

In this case, the execution context is an element from the DOM. That is what kicked off the click() method, which used the playGig function as a callback. So, this will end up with an undefined value.

在这种情况下, 执行上下文是DOM中的元素。 这就是click()方法的开始,该方法使用playGig函数作为回调 。 因此, 将以不确定的值结束。

In our analogy, this means that your band showed up to the competition with all their instruments, got in position to play, and then stared at the crowd like it was going to tell them what to do. It means you have forgotten the context of why you were there in the first place.

以我们的类比来说,这意味着您的乐队参加了所有乐器的比赛,可以演奏,然后凝视人群,就像要告诉他们该怎么做。 这意味着您首先忘记了为什么要呆在那里的背景。

To solve this, we need to use the bind() method to make sure that the playGig method still references the battle object, even when we call it from the context of a different object! It looks like this:

为了解决这个问题,我们需要使用bind()方法来确保playGig方法仍然引用战斗对象,即使从另一个对象的上下文调用它也是如此! 看起来像这样:

$('#annualBattle').click(battle.playGig.bind(battle)); //"We are going to be playing music from acdc tonight!"

Now, we get the correct output, even though the context was a DOM element.

现在,即使上下文是DOM元素,我们也能获得正确的输出。

使功能脱离上下文 (Pulling A Function Out of Context)

Let’s say that we wanted to write the code that will allow us to practice for the Battle of the Bands event. We will create a separate variable called practice, and assign the playGig method from the battle object.

假设我们想编写代码,使我们能够练习乐队战斗。 我们将创建一个名为实践单独的变量,并指定由战斗对象的playGig 方法

var artist= "Billy Joel";
function playGig(){  //instruments that your band will use   let instruments= ["piano", "microphone", "acousticGuitar", "harmonica"];
console.log("We are going to be playing music from " + this.artist + "tonight!"); }
let battle = {  artist:"acdc",   playGig: function(){     //instruments that your band will use     let instruments= ["microphone", "electricguitar", "bass", "drumset"];
console.log("We are going to be playing music from " + this.artist + "tonight!");   } }
let practice = battle.playGig; //run a practice practice();

So you are probably wondering: what is the execution context of the last line?

因此,您可能想知道:最后一行的执行上下文是什么?

Well, this will run into a similar problem as the previous example. When we create the practice variable, we are now storing an instance of the playGig method in the global context! It is no longer in the context of the battle object.

好吧,这将遇到与前面的示例类似的问题。 当我们创建练习变量时,我们现在将playGig方法的实例存储在全局上下文中 ! 它不再是在战斗对象的上下文中。

If we ran the code above, we would get:

如果运行上面的代码,则会得到:

practice();
//"We are going to be playing music from Billy Joel tonight!"

Not what we want. We are trying to practice AC/DC, and instead practicing Billy Joel. Yikes.

不是我们想要的。 我们正在尝试练习AC / DC,而是练习Billy Joel。 kes

Instead, we need to use the bind() method just like above. This will allow us to bind the context of the battle object.

相反,我们需要像上面一样使用bind()方法。 这将使我们能够绑定战斗对象的上下文。

let practice = battle.playGig.bind(battle);
practice(); //"We are going to be playing music from AC/DC tonight!"

匿名函数如何影响上下文 (How Anonymous Functions Affect Context)

Let’s say that your gig is coming to a close, and you want to give a shoutout to everyone in your band so that the crowd can give each person a round of applause.

假设您的演出即将结束,并且您想对乐队中的每个人大喊大叫,以便群众可以给每个人鼓掌。

In order to do this, we are going to use the forEach() method to iterate through each element in the value of the instruments property. (You will see why we changed it from a variable to a property in a moment). It will look like this:

为了做到这一点,我们将使用forEach()方法来遍历instruments属性值中的每个元素。 (您将看到为什么我们马上将其从变量更改为属性)。 它看起来像这样:

let battle = {  artist:"acdc",
//instruments that your band will use  instruments: ["microphone", "electricguitar", "bass", "drumset"],
shoutout: function(){
this.instruments.forEach(function(instrument){      console.log("Give a shoutout to my friend for covering the " + instrument + " from " + this.artist + "!");     }   } }
battle.shoutout();

But yet again, if we ran this code, it would not work.

但是同样,如果我们运行这段代码,它将无法正常工作。

It all centers around the line where we declare an anonymous function to use on each element in instruments. When this function is executed, the first this will retain the correct context: the battle object.

所有这些都围绕我们在其中声明要在工具中的每个元素上使用的匿名函数的那一行。 当执行此功能时,首先,这将保留正确的上下文: 战斗对象。

But, when we arrive at this.artist in the console.log statement, we will get… “Billy Joel”. This is because of the anonymous function that is used as a callback in the forEach() method. It resets the scope to the global scope.

但是,当我们在console.log语句中到达this.artist时,我们将得到“ Billy Joel”。 这是因为匿名函数在forEach()方法中用作回调。 它将范围重置为全局范围。

In this case, that means we would claim at the end to be playing Billy Joel… d’oh!

在这种情况下,这意味着我们最终会声称自己正在玩Billy Joel ... d'哦!

But here’s what we can do. We can create a new variable called that to store this in the correct context. Then, when we reference the artist that we played in this specific gig, we can reference the stored context, rather than being forced to return to global context.

但是,这就是我们可以做的。 我们可以创建一个名为存储在正确的背景下新的变量。 然后,当我们参考在该特定演出中扮演的艺术家时,我们可以参考存储的上下文,而不必强迫返回全局上下文。

let battle = {  artist:"acdc",  //instruments that your band will use   instruments: ["microphone", "electricguitar", "bass", "drumset"],   shoutout: function(){
//store context of this     let that = this;
this.instruments.forEach(function(instrument){      console.log("Give a shoutout to my friend for covering the " + instrument + " from " + that.artist + "!");    }   } }
battle.shoutout();

获取最新教程 (Get The Latest Tutorials)

Did you enjoy this tutorial? If you did, give it a clap or sign up for the latest visual tutorials from CodeAnalogies here:

您喜欢本教程吗? 如果您这样做了,请鼓掌或在此处注册CodeAnalogies的最新视觉教程:

翻译自: https://www.freecodecamp.org/news/javascripts-this-explained-by-starting-a-high-school-band-e072c8035eae/


http://lihuaxi.xjx100.cn/news/239595.html

相关文章

计算机防火墙不能启动,windows防火墙不能启动错误5

有的用户因为之前的原因关闭了防火墙,又因为某些原因需要打开防火墙,却提示防火墙不能启动,错误代码5。下面让学习啦小编为大家整理一些关于这个问题的解决答案,希望能帮到大家。Windows防火墙不能启动错误5的解决方法&#xff1a…

两个主键怎么设置tsql_索引该怎么创建?

1.2、索引 BTree 结构的特性:①、BTree 只有叶子节点会存储真实的数据,非叶子节点只会存储索引字段值;②、BTree的叶子节点之间使用 双向链表 链接,所以更加适合范围查询和排序;2、索引的类型:在平时创建的…

Mac 下 IDEA 启动慢的问题

转自&#xff1a; http://blog.csdn.net/KingBoyWorld/article/details/73440717 从控制台来看&#xff0c;每次都会连接本地地址(127.0.0.1)&#xff0c;问题可能就出在这里。 修改本地/etc/hosts文件&#xff0c;添加以下内容: 127.0.0.1 localhost <hostname&g…

Python函数式编程-map/reduce

1.map map()传入的第一个参数是f&#xff0c;即函数对象本身。 map()函数接收两个参数&#xff0c;一个是函数&#xff0c;一个是Interable&#xff0c;map将传入的函数依次作用到序列的每个元素&#xff0c;并把结果作为新的Iterator返回。 >>> def f(x): ... re…

刚刚重做系统的计算机开机时间很慢,U盘重装系统后电脑开机慢该怎么解决?解决电脑开机慢的方法...

U盘重装系统后电脑开机很慢怎么办?很多用户都经常遇到这种情况&#xff0c;使用了win10系统一段时间之后&#xff0c;电脑运行速度开始变慢。这个时候有些用户就会选择使用u盘重装系统来解决这个问题。但是&#xff0c;电脑重装系统之后&#xff0c;反而开机变得很慢&#xff…

冒泡排序_python实现冒泡排序

冒泡排序是比较经典的面试题&#xff0c; 它重复地走访过要排序的元素列&#xff0c;依次比较两个相邻的元素&#xff0c;如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换&#xff0c;也就是说该元素列已经…

开源贡献 计算_如何克服恐惧并为开源做贡献

开源贡献 计算Are you a new developer? Or maybe even just an old-timer who has been in a company for ten years, working on an in-house project, and now you’re thinking, “Hey, I’ve been in my box a long time. What’s new out there?” I have been like th…

Android开发之SharedPreferences的封装

对于大部分初学者来说&#xff0c;如果想利用SharedPreferences进行数据存储的话大部分人(包括本人)应该会这样&#xff1a; 存储&#xff1a; SharedPreferences sharedPreferences getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE); Editor editor …