javascript闭包
by Kevin Kononenko
凯文·科诺年科(Kevin Kononenko)
通过邮寄包裹解释JavaScript闭包 (JavaScript Closures Explained by Mailing a Package)
如果您以前寄过包裹或信件,那么您可以了解JavaScript中的闭包。 (If you have mailed a package or letter in the past, then you can understand closures in JavaScript.)
On your journey to becoming an intermediate or advanced JavaScript dev, you may have come across closures. After reading a technical resource on the subject… you also probably ran in the opposite direction.
在成为中级或高级JavaScript开发人员的过程中,您可能会遇到闭包的情况。 阅读有关该主题的技术资源之后,您可能也朝相反的方向奔跑。
Here is the awesome thing about closures: they allow you to write functions with an intermediate step that can capture data from your site at a specific moment in time. It’s like adding a ‘pause’ button to your function. You can run your function and save the value of a variable at that particular point in time. Then, when you want to resume the function at a later point and use values of variables that have changed within your app… you can do that with a closure, or a function within the original function.
这是关于闭包的很棒的事情 :它们允许您编写带有中间步骤的函数,该中间步骤可以在特定时间捕获站点中的数据。 这就像在功能中添加“暂停”按钮一样。 您可以运行函数并在该特定时间点保存变量的值。 然后,当您想在以后恢复该功能并使用在您的应用程序中已更改的变量的值时...您可以使用闭包或原始功能中的一个功能来实现 。
This gets easier, I promise.
我保证,这会变得更容易。
So, when the heck would you use a closure?
那么,什么时候使用闭包呢?
Let’s say you are building an interactive map of tourist landmarks in New York City using the Google Maps API. You have an array with a bunch of map markers that you want to add to the map- the Statue of Liberty, Empire State Building, Coney Island, you name it. You want to add all these markers to the map, but you also want to add a click event to each marker. When you click the marker, you want to show dynamic information about that marker, including live weather data.
假设您正在使用Google Maps API构建纽约市旅游地标的交互式地图。 您有一个包含一堆要添加到地图的地图标记的数组-自由女神像,帝国大厦,康尼岛,您将其命名。 您想将所有这些标记添加到地图,但也想将click事件添加到每个标记。 单击标记时,您要显示有关该标记的动态信息,包括实时天气数据。
var touristPlaces= […];
for(var i=0; i< touristPlaces.length; i++){ var marker= touristPlaces[i]; $(marker).click(function(){ showToolTip(i) });}
Here’s the issue- if you write it like this, it will not work. The ‘for’ loop will finish before the callback in the click event can register the appropriate i value. You need to capture this intermediate point so you can call the function later with the appropriate i.
这是问题所在-如果您这样编写, 它将无法正常工作 。 在单击事件中的回调可以注册适当的i值之前,“ for”循环将完成。 您需要捕获此中间点,以便稍后可以使用适当的i调用该函数。
What do you need to know first?
您首先需要了解什么?
- Variable scoping 可变范围
The concept of callbacks (I wrote a guide on this too!)
回调的概念(我也为此写过指南 !)
If you are looking for a technical explanation of closures, the guide on MDN is probably the best.
如果您正在寻找有关闭包的技术说明, 则有关MDN的指南可能是最好的。
关闭与邮寄包裹的过程相同。 (Closures have the same process as mailing a package.)
Let’s look at some basic code that uses a closure to mail a package.
让我们看一些使用闭包邮寄包裹的基本代码。
The addressPackage() function is a closure! It can be called at any time after the packBox function has been called. It also has access to the variables and arguments from the time when packBox() was originally called.
addressPackage()函数是一个闭包 ! 可以在调用packBox函数后随时调用它。 从最初调用packBox()以来,它还可以访问变量和参数。
Notice how the console.log output does not show until lines 14 and 15? This is extremely important. If you ran this code after line 11, you would simply see ‘Put jersey in box’. There would be no error, but the closure, addressPackage(), would not run at that point.
请注意console.log输出如何直到第14和15行才显示? 这是非常重要的。 如果您在第11行之后运行此代码,则只会看到“将球衣放入框中”。 不会有错误,但是闭包addressPackage()不会在此时运行。
When you are mailing a package, you would probably agree that your job is not done until the package is filled and the address is written. Likewise, the packBox() function waits until the closure has also been called. Let’s go through this line-by-line.
当您邮寄包裹时,您可能会同意在填满包裹并写出地址之前不会完成您的工作。 同样,packBox()函数将等待,直到还调用了闭包。 让我们逐行进行介绍。
Line 11: You create the variable brotherGift, which is an instance of the packBox() function. You are sending a jersey to your brother.
第11行:创建变量brotherGift,它是packBox()函数的一个实例 。 您正在向您的兄弟发送球衣。
Line 3: Your code logs a statement about the jersey.
第3行:您的代码记录了有关球衣的声明。
Line 8: The packBox() function returns… another function? Huh?
第8行: packBox()函数返回…另一个函数? ??
Let’s stop here, and assume that line 13 has not run yet. Here is what is happening: The packBox() function will not return the “ready to send” line until you also call the addressPackage() function with an argument. Just like there are two steps to sending a package: first, filling it, and second, addressing it. Your package is worthless if it has no contents or it does not have an address! That being said, you do not necessarily need to address the package directly after you fill the contents. You can wait a few days before addressing it. You might need to go to your computer to look up the address. You might be waiting for your brother to officially change his address!
让我们在这里停止,并假设第13行尚未运行。 这是发生的情况:在您还使用参数调用addressPackage()函数之前,packBox()函数将不会返回“准备发送”行。 就像发送包裹有两个步骤一样:第一步,填充包裹,第二步,处理包裹。 如果您的包裹没有物品或没有地址,那将毫无价值! 话虽如此,填写内容后,您不一定需要直接处理包裹。 您可以等待几天,然后再解决。 您可能需要转到计算机以查找地址。 您可能正在等待您的兄弟正式更改他的地址!
Regardless, if you do not address the package immediately, this does not mean that the package will somehow magically empty itself. The contents will still be there when you return to address it! So, any time we call brotherGift, the first argument, jersey, will still be available.
无论如何,如果您不立即处理该软件包,这并不意味着该软件包将以某种方式神奇地清空其自身。 返回地址时内容仍然在那里! 因此,无论何时我们将其称为brotherGift,第一个参数jersey仍然可用。
…Waiting…Waiting…Now let’s run line 13.
…正在等待…正在等待…现在运行第13行。
Line 13: Alright, let’s finish off this instance! You are ready to add the address, so you call brotherGift and offer the address as an argument. Remember from line 11, brotherGift is an instance of packBox with the ‘jersey’ argument. So when you call it, you are offering another argument, which will then be sent to the closure: addressPackage();
第13行:好的,让我们结束这个实例 ! 您已经准备好添加地址,因此可以调用brotherGift并提供该地址作为参数。 请记住,从第11行开始,brotherGift是带有'jersey'参数的packBox的实例 。 因此,当您调用它时,您将提供另一个参数,然后将其发送到闭包:addressPackage();
Line 3: The console.log will show since we are now running the code from line 13.
第3行:由于我们现在正在运行第13行的代码,因此将显示console.log。
Line 4: We now offer the second argument to addressPackage();
第4行:现在,我们为addressPackage()提供第二个参数;
Line 6: addressPackage logs a statement related to the address argument.
第6行: addressPackage记录与address参数相关的语句。
Line 8: The return statement can fire for this instance.
第8行: return语句可以为此实例触发。
Again, closures allow us to have this intermediate instance where one argument has been filled, but brotherGift is left unfulfilled until we add the second argument. If we wanted to do this in one line, we would write: packBox(‘jersey’)(‘123 Main Street, Anywhere USA 01234’);
再次,闭包允许我们拥有一个已填充一个参数的中间实例,但是在添加第二个参数之前,不执行brotherGift。 如果要在一行中执行此操作 ,则应编写:packBox('jersey')('123 Main Street,Anywhere USA 01234');
再举一个例子 (One More Example)
Let’s say that you wanted to send a gift to each member of your family. You might pack each box before adding the addresses to each. This is what that looks like in code.
假设您想发送礼物给家人。 您可以在将每个地址添加到每个地址之前打包它们。 这就是代码中的样子。
Another magical feature of closures! Each instance is able to use the correct gift item with the correct address, even thought we run the function with 4 separate gift/address pairs. In a traditional function, there is no concept of memory. You would need to explicitly restate the original gifts in lines 6–15 if you wanted to use a traditional function.
关闭的另一个神奇功能! 每个实例都能够使用具有正确地址的正确礼物项目,即使我们以4个单独的礼物/地址对运行该功能也是如此。 在传统功能中,没有内存的概念。 如果要使用传统功能,则需要在第6-15行中明确声明原始礼物。
您将在哪里使用 (Where You Will Use This)
You will frequently encounter closures in Node.js. If you are just interested in the front-end, think back to our original example. If you want to write a function that considers user input at two separate stages of your app, you may want to consider a closure!
您将经常在Node.js中遇到闭包。 如果您只是对前端感兴趣,请回想一下我们最初的示例。 如果要编写一个在应用程序的两个单独阶段考虑用户输入的函数,则可能需要考虑闭包!
Did you enjoy this guide? Or are you having trouble with another JavaScript topic? Give it a heart and let me know in the comments!
您喜欢本指南吗? 还是您在处理另一个JavaScript主题时遇到麻烦? 放心,让我在评论中知道!
Looking for other JavaScript concepts explained? Check out these past articles in the series.
寻找其他解释过JavaScript概念吗? 查看本系列中的这些过去的文章。
JavaScript Promises Explained By Gambling At A Casino
Model-View-Controller (MVC) Explained Through Ordering Drinks At The Bar
JavaScript Callbacks Explained Using Minions
翻译自: https://www.freecodecamp.org/news/javascript-closures-explained-by-mailing-a-package-4f23e9885039/
javascript闭包