2799
5763
這個問題的答案是社區的努力。編輯現有答案以改善此職位。它目前不接受新的答案或互動。
您將如何向了解了閉包本身的概念(例如函數,變量等)的人解釋JavaScript閉包,但卻不了解閉包本身?
我已經在Wikipedia上看到了Scheme示例,但是不幸的是它沒有幫助。 
1個
2
3
下一個
閉包是以下各項的配對:
一個功能,以及
對函數外部範圍的引用(詞法環境)
詞法環境是每個執行上下文(堆棧框架)的一部分,並且是標識符(即局部變量名稱)和值之間的映射。
JavaScript中的每個函數都對其外部詞彙環境保持引用。此引用用於配置調用函數時創建的執行上下文。此引用使函數內部的代碼可以“查看”在函數外部聲明的變量,而不管調用函數的時間和位置。
如果一個函數被一個函數調用,而另一個函數又調用了另一個函數,則將創建對外部詞彙環境的引用鏈。該鏈稱為作用域鏈。
在以下代碼中,inner與調用foo時創建的執行上下文的詞法環境形成一個閉包,從而對變量secret進行關閉:
函數foo(){
const secret = Math.trunc(Math.random()* 100)
返回函數inner(){
console.log(`秘密號是$ {secret}。`)
}
}
const f = foo()//無法從外部`foo`直接訪問`secret`
f()//檢索“秘密”的唯一方法是調用“ f”
換句話說:在JavaScript中,函數帶有對私有“狀態框”的引用,只有它們(以及在相同詞法環境中聲明的任何其他函數)可以訪問。該狀態框對於函數的調用者是不可見的,從而為數據隱藏和封裝提供了一種出色的機制。
請記住:JavaScript中的函數可以像變量一樣傳遞(一流的函數),這意味著功能和狀態對可以在程序中傳遞:類似於您在C ++中傳遞類的實例的方式。
如果JavaScript沒有閉包,則必須在函數之間顯式傳遞更多狀態,從而使參數列表更長,代碼更嘈雜。
因此,如果您希望函數始終有權訪問私有狀態,則可以使用閉包。
...而且我們經常想將狀態與函數關聯。例如,在Java或C ++中,當您將私有實例變量和方法添加到類時,您正在將狀態與功能相關聯。
在C語言和大多數其他常見語言中,函數返回後,所有本地變量將不再可訪問,因為堆棧框架被破壞了。在JavaScript中,如果在另一個函數中聲明一個函數,則外部函數從其返回後仍可訪問。這樣,在上面的代碼中,機密在從foo返回後仍可用於函數對象內部。
閉包的使用
每當需要與函數關聯的私有狀態時,閉包都是有用的。這是一個非常常見的情況-請記住:JavaScript直到2015年才使用類語法,並且仍然沒有私有字段語法。封閉件可滿足此需求。
私有實例變量
在以下代碼中,函數toString關閉了汽車的詳細信息。
功能Car(製造商,型號,年份,顏色){
返回{
toString(){
返回`$ {manufacturer} $ {model}($ {year},$ {color})`
}
}
}
const car = new Car('Aston Martin','V8 Vantage','2012','Quantum Silver')
console.log(car.toString())
功能編程
在以下代碼中,函數inner關閉fn和args。
函數curry(fn){
const args = []
返回函數inner(arg){
if(args.length === fn.length)返回fn(... args)
args.push(arg)
返回內部
}
}
函數add(a,b){
返回a + b
}
const curriedAdd =咖哩(添加)
console.log(curriedAdd(2)(3)())// 5
面向事件的程序設計
在以下代碼中,函數onClick關閉變量Background_COLOR。
const $ = document.querySelector.bind(document)
const Background_COLOR ='rgba(200,200,242,1)'
函數onClick(){
$('body')。style.background =背景顏色
}
$('button')。addEventListener('click',onClick)