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
在賭場賭博解釋JavaScript承諾
Model-View-Controller (MVC) Explained Through Ordering Drinks At The Bar
通過在酒吧訂購飲料來解釋模型視圖控制器(MVC)
JavaScript Callbacks Explained Using Minions
使用Minions解釋JavaScript回調
翻譯自: https://www.freecodecamp.org/news/javascript-closures-explained-by-mailing-a-package-4f23e9885039/
javascript閉包