javascript閉包_JavaScript閉包教程–帶有JS閉包示例代碼

javascript閉包

Closures – many of you JavaScript devs have probably heard this term before. When I started my journey with JavaScript, I encountered closures often. And I think they're one of the most important and interesting concepts in JavaScript.

閉包–您中的許多JavaScript開發人員以前可能都聽說過這個詞。 當我開始使用JavaScript時,經常會遇到關閉。 而且我認為它們是JavaScript中最重要和最有趣的概念之一。

You don't think they're interesting? This often happens when you don’t understand a concept – you don’t find it interesting. (I don’t know if this happens to you or not, but this is the case with me).

你不覺得他們有趣嗎? 當您不了解某個概念時,通常會發生這種情況–您不覺得它很有趣。 (我不知道這是否發生在您身上,但我就是這種情況)。

So in this article, I will try to make closures interesting for you.

因此,在本文中,我將嘗試使閉包變得有趣。

Before going into the world of closures, let’s first understand lexical scoping. If you already know about it, skip the next part. Otherwise jump into it to better understand closures.

在進入閉包世界之前,讓我們首先了解詞法作用域 。 如果您已經知道它,請跳過下一部分。 否則,請跳入其中以更好地了解閉包。

詞匯范圍 (Lexical Scoping )

You may be thinking – I know local and global scope, but what the heck is lexical scope? I reacted the same way when I heard this term. Not to worry! Let’s take a closer look.

您可能在想–我知道本地和全球范圍,但是詞匯范圍到底是什么呢? 聽到這個學期時,我的React是一樣的。 不要擔心! 讓我們仔細看看。

It’s simple like other two scopes:

就像其他兩個作用域一樣簡單:

function greetCustomer() {var customerName = "anchal";function greetingMsg() {console.log("Hi! " + customerName); // Hi! anchal}greetingMsg();
}

You can see from the above output that the inner function can access the outer function's variable. This is lexical scoping, where the scope and value of a variable is determined by where it is defined/created (that is, its position in the code). Got it?

從上面的輸出中可以看到,內部函數可以訪問外部函數的變量。 這是詞法作用域,其中變量的范圍和值由定義/創建的位置(即其在代碼中的位置)確定。 得到它了?

I know that last bit might have confused you. So let me take you deeper. Did you know that lexical scoping is also known as static scoping? Yes, that's its other name.

我知道最后一點可能會讓您感到困惑。 因此,讓我更深入地介紹您。 您是否知道詞法作用域也稱為靜態作用域 ? 是的,這是它的別稱。

There is also dynamic scoping, which some programming languages support. Why have I mentioned dynamic scoping? Because it can help you better understand lexical scoping.

還有動態范圍 ,某些編程語言支持。 為什么提到動態范圍? 因為它可以幫助您更好地理解詞法作用域。

Let’s look at some examples:

讓我們看一些例子:

function greetingMsg() {console.log(customerName);// ReferenceError: customerName is not defined
}function greetCustomer() {var customerName = "anchal";greetingMsg();
}greetCustomer();

Do you agree with the output? Yes, it will give a reference error. This is because both functions don’t have access to each other’s scope, as they are defined separately.

您是否同意輸出? 是的,它將給出參考錯誤。 這是因為這兩個函數無法訪問彼此的范圍,因為它們是分別定義的。

Let’s look at another example:

讓我們看另一個例子:

function addNumbers(number1) {console.log(number1 + number2);
}function addNumbersGenerate() {var number2 = 10;addNumbers(number2);
}addNumbersGenerate();

The above output will be 20 for a dynamically scoped language. Languages that support lexical scoping will give referenceError: number2 is not defined. Why?

對于動態范圍的語言,以上輸出將為20。 支持詞法作用域的語言會給 referenceError: number2 is not defined 。 為什么?

Because in dynamic scoping, searching takes place in the local function first, then it goes into the function that called that local function. Then it searches in the function that called that function, and so on, up the call stack.

因為在動態作用域中,搜索首先在本地函數中進行,然后才進入調用該本地函數的函數中。 然后,它在調用函數的函數中進行搜索,依此類推,直到調用堆棧。

Its name is self explanatory – “dynamic” means change. The scope and value of variable can be different as it depends on from where the function is called. The meaning of a variable can change at runtime.

它的名字不言自明–“動態”意味著變化。 變量的范圍和值可以不同,這取決于調用函數的位置。 變量的含義可以在運行時更改。

Got the gist of dynamic scoping? If yes, then just remember that lexical scoping is its opposite.

有動態范圍的要點嗎? 如果是,那么請記住詞匯范圍是相反的。

In lexical scoping, searching takes place in the local function first, then it goes into the function inside which that function is defined. Then it searches in the function inside which that function is defined and so on.

在詞法作用域中,搜索首先在局部函數中進行,然后進入定義函數的函數中。 然后,它在定義函數的函數中進行搜索,依此類推。

So, lexical or static scoping means the scope and value of a variable is determined from where it is defined. It doesn’t change.

因此, 詞匯靜態作用域意味著從定義變量的位置確定變量的范圍和值。 它沒有改變。

Let’s again look at the above example and try to figure out the output on your own. Just one twist – declare number2 at the top:

讓我們再次看一下上面的示例,嘗試自己找出輸出。 只需一轉-在頂部聲明數字number2

var number2 = 2;
function addNumbers(number1) {console.log(number1 + number2);
}function addNumbersGenerate() {var number2 = 10;addNumbers(number2);
}addNumbersGenerate();

Do you know what the output will be?

您知道輸出是什么嗎?

Correct – it’s 12 for lexically scoped languages. This is because first, it looks into an addNumbers function (innermost scope) then it searches inwards, where this function is defined. As it gets the number2 variable, meaning the output is 12.

正確–詞匯范圍語言為12。 這是因為,首先,它查看一個addNumbers函數(最內部的作用域),然后向內搜索,在其中定義了此函數。 當它獲得number2變量時,意味著輸出為12。

You may be wondering why I have spent so much time on lexical scoping here. This is a closure article, not one about lexical scoping. But if you don’t know about lexical scoping then you will not understand closures.

您可能想知道為什么我在這里花了這么多時間進行詞匯界定。 這是一篇閉篇文章,而不是有關詞法作用域的文章。 但是,如果您不了解詞法作用域,那么您將不會理解閉包。

Why? You will get your answer when we look at the definition of a closure. So let’s get into the track and get back to closures.

為什么? 當我們查看閉包的定義時,您會得到答案。 因此,讓我們進入正軌,回到閉包。

什么是閉包? (What is a Closure? )

Let’s look at the definition of a closure:

讓我們看一下閉包的定義:

Closure is created when an inner function has access to its outer function variables and arguments. The inner function has access to –

當內部函數可以訪問其外部函數的變量和參數時,將創建閉包。 內部功能可以訪問–

1. Its own variables.

1.自己的變量。

2. Outer function's variables and arguments.

2.外部函數的變量和參數。

Wait! Is this the definition of a closure or lexical scoping? Both definitions look the same. How they are different?

等待! 這是閉包或詞匯作用域的定義嗎? 兩種定義看起來相同。 它們有何不同?

Well, that's why I defined lexical scoping above. Because closures are related to lexical/static scoping.

好吧,這就是為什么我在上面定義詞法作用域的原因。 因為閉包與詞匯/靜態作用域有關。

Let’s again look at its other definition that will tell you how closures are different.

讓我們再次查看其另一個定義,該定義將告訴您閉包有何不同。

Closure is when a function is able to access its lexical scope, even when that function is executing outside its lexical scope.
閉包是指某個函數能夠訪問其詞法范圍,即使該函數正在其詞法范圍之外執行。

Or,

要么,

Inner functions can access its parent scope, even after the parent function is already executed.
內部函數可以訪問其父范圍,即使已經執行了父函數也是如此。

Confused? Don't worry if you haven't yet gotten the point. I have examples to help you better understand. Let’s modify the first example of lexical scoping:

困惑? 如果您還沒有明白這一點,請不要擔心。 我有一些例子可以幫助您更好地理解。 讓我們修改詞法作用域的第一個示例:

function greetCustomer() {const customerName = "anchal";function greetingMsg() {console.log("Hi! " + customerName);}return greetingMsg;
}const callGreetCustomer = greetCustomer();
callGreetCustomer(); // output – Hi! anchal

The difference in this code is that we are returning the inner function and executing it later. In some programming languages, the local variable exists during the function’s execution. But once the function is executed, those local variables don’t exist and they will not be accessible.

這段代碼的區別在于我們要返回內部函數并在以后執行它。 在某些編程語言中,局部變量在函數執行期間存在。 但是一旦函數執行完畢,這些局部變量將不存在,并且將無法訪問。

Here, however, the scene is different. After the parent function is executed, the inner function (returned function) can still access the parent function's variables. Yes, you guessed right. Closures are the reason.

但是,這里的場景有所不同。 執行父函數后,內部函數(返回的函數)仍可以訪問父函數的變量。 是的,你猜對了。 停業是原因。

The inner function preserves its lexical scope when the parent function is executing and hence, later that inner function can access those variables.

內部函數在執行父函數時會保留其詞法范圍,因此以后內部函數可以訪問這些變量。

To get a better feel for it, let’s use the dir() method of the console to look into the list of the properties of callGreetCustomer:

為了更好地了解它,讓我們使用控制臺的dir()方法查看callGreetCustomer屬性的callGreetCustomer

console.dir(callGreetCustomer);

From the above image, you can see how the inner function preserves its parent scope (customerName) when greetCustomer() is executed. And later on, it used customerName when callGreetCustomer() was executed.

從上面的圖像中,您可以看到執行greetCustomer()時內部函數如何保留其父范圍( customerName )。 之后,當執行callGreetCustomer()時,它使用了customerName

I hope this example helped you better understand the above definition of a closure. And maybe now you find closures a bit more fun.

我希望這個例子可以幫助您更好地理解閉包的上述定義。 也許現在您發現關閉更有趣了。

So what next? Let’s make this topic more interesting by looking at different examples.

那接下來呢? 通過查看不同的示例,使這個話題變得更加有趣。

實施中的關閉示例 (Examples of closures in action)

function counter() {let count = 0;return function() {return count++;};
}const countValue = counter();
countValue(); // 0
countValue(); // 1
countValue(); // 2

Every time you call countValue, the count variable value is incremented by 1. Wait – did you think that the value of count is 0?

每次調用countValue ,count變量的值都會增加1。等待–您是否認為count的值為0?

Well, that would be wrong as a closure doesn’t work with a value. It stores the reference of the variable. That’s why, when we update the value, it reflects in the second or third call and so on as the closure stores the reference.

嗯,這是錯誤的,因為閉包不能與值一起使用。 它存儲變量的引用 。 這就是為什么當我們更新值時,它會在第二個或第三個調用中反映出來,依此類推,因為閉包存儲了引用。

Feeling a bit clearer now? Let’s look at another example:

現在感覺更清晰了嗎? 讓我們看另一個例子:

function counter() {let count = 0;return function () {return count++;};
}const countValue1 = counter();
const countValue2 = counter();
countValue1();  // 0
countValue1();  // 1
countValue2();   // 0
countValue2();   // 1

I hope you guessed the right answer. If not, here is the reason. As countValue1 and countValue2, both preserve their own lexical scope. They have independent lexical environments. You can use dir() to check the [[scopes]] value in both the cases.

希望您猜對了答案。 如果沒有,這就是原因。 與countValue1countValue2 ,它們都保留了自己的詞匯范圍。 他們有獨立的詞匯環境。 在這兩種情況下,都可以使用dir()檢查[[scopes]]值。

Let’s look at a third example.

讓我們看第三個例子。

This one's a bit different. In it, we have to write a function to achieve the output:

這有點不同。 在其中,我們必須編寫一個函數來實現輸出:

const addNumberCall = addNumber(7);
addNumberCall(8) // 15
addNumberCall(6) // 13

Simple. Use your newly-gained closure knowledge:

簡單。 使用您新獲得的閉包知識:

function addNumber(number1) {return function (number2) {return number1 + number2;};
}

Now let’s look at some tricky examples:

現在讓我們看一些棘手的例子:

function countTheNumber() {var arrToStore = [];for (var x = 0; x < 9; x++) {arrToStore[x] = function () {return x;};}return arrToStore;
}const callInnerFunctions = countTheNumber();
callInnerFunctions[0]() // 9
callInnerFunctions[1]() // 9

Every array element that stores a function will give you an output of 9. Did you guess right? I hope so, but still let me tell you the reason. This is because of the closure's behavior.

每個存儲函數的數組元素都將為您提供9的輸出。您猜對了嗎? 希望如此,但還是讓我告訴您原因。 這是由于閉包的行為。

The closure stores the reference, not the value. The first time the loop runs, the value of x is 0. Then the second time x is 1, and so on. Because the closure stores the reference, every time the loop runs it's changing the value of x. And at last, the value of x will be 9. So callInnerFunctions[0]() gives an output of 9.

閉包存儲引用 ,而不是值。 循環第一次運行時,x的值為0。然后第二次循環x為1,依此類推。 因為閉包存儲引用,所以每次循環運行時,它都會更改x的值。 最后,x的值為9。因此callInnerFunctions[0]()的輸出為9。

But what if you want an output of 0 to 8? Simple! Use a closure.

但是,如果您想要0到8的輸出怎么辦? 簡單! 使用閉包。

Think about it before looking at the solution below:

在查看以下解決方案之前,請考慮一下:

function callTheNumber() {function getAllNumbers(number) {return function() {return number;};}var arrToStore = [];for (var x = 0; x < 9; x++) {arrToStore[x] = getAllNumbers(x);}return arrToStore;
}const callInnerFunctions = callTheNumber();
console.log(callInnerFunctions[0]()); // 0
console.log(callInnerFunctions[1]()); // 1

Here, we have created separate scope for each iteration. You can use console.dir(arrToStore) to check the value of x in [[scopes]] for different array elements.

在這里,我們為每次迭代創建了單獨的作用域。 您可以使用console.dir(arrToStore)檢查[[scopes]]中x的值以獲取不同的數組元素。

That’s it! I hope you can now say that you find closures interesting.

而已! 我希望您現在可以說您發現閉包很有趣。

To read my other articles, check out my profile here.

要閱讀其他文章,請在此處查看我的個人資料。

翻譯自: https://www.freecodecamp.org/news/javascript-closure-tutorial-with-js-closure-example-code/

javascript閉包

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/390263.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/390263.shtml
英文地址,請注明出處:http://en.pswp.cn/news/390263.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

1646. 獲取生成數組中的最大值

1646. 獲取生成數組中的最大值 給你一個整數 n 。按下述規則生成一個長度為 n 1 的數組 nums &#xff1a; nums[0] 0 nums[1] 1 當 2 < 2 * i < n 時&#xff0c;nums[2 * i] nums[i] 當 2 < 2 * i 1 < n 時&#xff0c;nums[2 * i 1] nums[i] nums[i …

docker保存日志文件到本地

其實很簡單 docker logs 你需要添加的額外參數 容器id >文件名稱 然后查看這個文件就可以了&#xff0c;也可以通過ftp協議下載到本地

防反射JavaScript –如何讓您的JS等待

Debounce methods do not execute when invoked. Instead, they wait for a predetermined time before executing. If the same method is called again, the previous is cancelled and the timer restarts.防抖動方法在調用時不執行。 而是&#xff0c;它們在執行之前等待預…

21天學通Visual.Basic pdf

下載地址&#xff1a;網盤下載《21天學通Visual Basic(第2版)》是Visual Basic 6.0的入門教程&#xff0c;主要針對沒有程序設計基礎的讀者&#xff0c;詳細介紹了Visual Basic 6.0的基本概念和編程技術。書中通過大量的范例及綜合練習來介紹Visual Basic 6.0的基本概念、語言特…

297. 二叉樹的序列化與反序列化

297. 二叉樹的序列化與反序列化 序列化是將一個數據結構或者對象轉換為連續的比特位的操作&#xff0c;進而可以將轉換后的數據存儲在一個文件或者內存中&#xff0c;同時也可以通過網絡傳輸到另一個計算機環境&#xff0c;采取相反方式重構得到原數據。 請設計一個算法來實現…

交互式圖表_如何構建羅馬數字轉換器和交互式羅馬數字圖表

交互式圖表The Roman numerals are no longer an essential part of our daily lives. But we do use them when designing monuments, clocks, and even for sporting events.羅馬數字不再是我們日常生活中必不可少的部分。 但是我們在設計紀念碑&#xff0c;鐘表甚至體育賽事…

Python 08 面向對象

Python 面向對象 1、編程范式 2、面向對象特性 3、屬性、方法 4、三大特性 5、高級方法 6、類的特殊成員方法 7、反射 8、異常處理 9、單例模式 一、編程范式 編程&#xff1a;程序員用特定的語法數據結構算法組成的代碼來告訴計算機如何執行任務的過程 &#xff0c; 實現一個…

eclipse手動添加SVN插件

https://www.cnblogs.com/hcl1991/p/5888461.html 1.手動下載svn插件&#xff08;百度SVNsite-1.8.18&#xff09; 2.將下載好的SVNsite-1.8.18.zip 解壓 3.在eclipse安裝目錄的plugins新建SVN文件夾 4.將SVNsite-1.8.18解壓包下的features和plugins拷貝到新建的SVN文件夾下 5.…

440. 字典序的第K小數字

440. 字典序的第K小數字 給定整數 n 和 k&#xff0c;找到 1 到 n 中字典序第 k 小的數字。 注意&#xff1a;1 ≤ k ≤ n ≤ 109。 示例 : 輸入: n: 13 k: 2 輸出: 10 解釋: 字典序的排列是 [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9]&#xff0c;所以第二小的數字是…

微信小程序 設置背景占滿整個頁面

微信小程序,默認的根節點是<page></page>&#xff0c;所有內容都包裹在這個標簽里&#xff0c;如何讓頁面的背景占滿整個屏幕&#xff1f;&#xff1f; <page><view class"bg">....</view> </page> .bg {background-image:ur…

udemy下載課程無法播放_最好的Udemy Web開發課程+熱門免費課程

udemy下載課程無法播放Heres a list of some of the most popular web development courses on Udemy:以下是Udemy上一些最受歡迎的Web開發課程的列表&#xff1a; Best General Web Development Courses on Udemy:關于Udemy的最佳常規Web開發課程&#xff1a; The Complete …

滲透測試初學者_滲透測試許可證:面向初學者的道德黑客課程

滲透測試初學者A penetration test is an authorized cyberattack on a computer system, performed to evaluate the security of the system. 滲透測試是對計算機系統的授權網絡攻擊&#xff0c;旨在評估系統的安全性。 Weve released a full pentesting course on the free…

Codeforces 915 E Physical Education Lessons

題目描述 This year Alex has finished school, and now he is a first-year student of Berland State University. For him it was a total surprise that even though he studies programming, he still has to attend physical education lessons. The end of the term is …

JDK 11 還有一個處于計劃階段的 JEP:讓其支持 TLS 1.3

開發四年只會寫業務代碼&#xff0c;分布式高并發都不會還做程序員&#xff1f; >>> JDK 11 最近有什么消息&#xff1f;我們不妨來看一下它的進展情況&#xff0c;包括最新的 JEP 提案。Java 的新版本發布計劃意味著總會有一款新的 JDK 即將推出。根據他們的計劃&a…

498. 對角線遍歷

498. 對角線遍歷 給定一個含有 M x N 個元素的矩陣&#xff08;M 行&#xff0c;N 列&#xff09;&#xff0c;請以對角線遍歷的順序返回這個矩陣中的所有元素&#xff0c;對角線遍歷如下圖所示。 示例: 輸入: [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ] 輸出: [1,2,4,7,5…

軟件測試測試用例編寫_不要先編寫所有軟件測試-只需編寫一個

軟件測試測試用例編寫Test Driven Development (TDD) is sometimes described as “writing tests first”. The TDD mantra states that we should not write code before we have written automated tests that exercise that code. Writing code first is considered subopt…

練習五

1.團隊模式和團隊的開發模式有什么關系&#xff1f; 答&#xff1a; 首先我來解釋一下這兩個名詞&#xff1a; 我查資料了解了一下&#xff0c;團隊模式&#xff0c;更偏向于多人合作的那種&#xff0c;而且我理解的“團隊”會是一種多人合作的情況下&#xff0c;長期磨合后的一…

Squid 訪問控制配置

Squid 訪問控制配置 主配置文件內加入限制參數 vim /etc/squid/squid.conf # 訪問控制 acl http proto HTTP # 限制訪問 good_domain添加兩個域名“.”表示半解析(相當于*) acl good_domain dstdomain .kevin.net .baidu.com # 允許good_domain內的域名訪問 http_access allow …

劍指 Offer 62. 圓圈中最后剩下的數字

0,1,,n-1這n個數字排成一個圓圈&#xff0c;從數字0開始&#xff0c;每次從這個圓圈里刪除第m個數字&#xff08;刪除后從下一個數字開始計數&#xff09;。求出這個圓圈里剩下的最后一個數字。 例如&#xff0c;0、1、2、3、4這5個數字組成一個圓圈&#xff0c;從數字0開始每…

rust 編程入門_面向初學者的Rust –最受歡迎的編程語言入門

rust 編程入門Rust has been voted Stack Overflow’s most loved programming language for five years in a row. This article will tell you why Rust is awesome.Rust已連續五年被評為Stack Overflow最受歡迎的編程語言。 本文將告訴您為什么Rust很棒。 Rust is a system…