2010-07-21 54 views
5

什麼是關閉及其對應示例?關閉定義和示例

我有很多研究,並不明白。 請在通用編程語言概念方面和具體編程語言方面進行說明。

請幫忙。

謝謝。

+0

問題http://stackoverflow.com/questions/36636/what-is-a-closure和http://stackoverflow.com/questions/1095707/what-is-the-exact-definition-of-a-閉包與此類似 – 2010-07-21 04:12:29

回答

1

這裏是我如何看待一個閉包......

一個函數對象由兩件事組成。第一件事是該函數的代碼,第二件事是它執行的範圍。在閉包中,函數執行的範圍和代碼相互分離。相同的代碼可以在各種範圍內執行。

如果以完全不受限制的方式允許這會導致很大的混淆。即使它和動態範圍一樣鬆散(函數繼承了它被調用的地方的範圍),它變得非常混亂。

閉包是一種指定範圍規則的便捷方式,因爲它們只需要讀取代碼而不是跟蹤代碼,因此很有意義。在閉包中,函數獲取聲明的範圍。如果它在執行另一個函數時被聲明,它將獲得函數堆棧的特定實例的範圍。與能夠給出閉包和任意範圍或動態範圍相比,這更簡單易懂。

這裏是在Python瑣碎閉合的一個示例:

def outer(): 
    def closure(): 
     pass 
    return closure 

在這裏,函數closure是一個閉合。它實際上並沒有使用它定義的範圍中的任何變量,所以它非常微不足道,但它仍然是一個。

這裏是Python中不那麼平凡,但還是單純縫合:

def outer(x): 
     def closure(): 
      return x 
     return closure 
f1 = outer(5) 
f2 = outer(6) 

調用f1()將返回5,並呼籲f2()將返回6.正如你所看到的,功能closure是部分代碼和部分範圍。

outer(5)被調用時,它爲呼叫創建一個包含一個版本的變量x持有價值5.然後,它宣佈它獲取該範圍的功能closure一個堆棧條目。

outer(6)被調用時,它爲呼叫創建一個包含一個版本的變量x持有價值6.然後宣佈其獲取範圍功能closure一個堆棧條目。

+0

感謝您的解釋 – peterwkc 2010-07-21 06:37:11

9

閉包基本上是嵌套在可以訪問本地變量函數的內部函數B:

function A() { 
    var x = 5; 

    function B() { 
     print(x); 
    } 

    return B; 
} 

如果你來自一個C++的背景下,這是相當難以消化。當我們嘗試調用A返回的函數時,它會引用什麼x?那x不會因爲A()終止而無效嗎?

答案是x實際上仍然存在。我們回到的B實際上帶着它隱含地帶着x。很酷,呃?

從一般意義上講,閉包是一個綁定到某些數據的函數。在沒有像C這樣的閉包的語言中,每個程序都有固定數量的函數。使用閉包,從某種意義上說,您可以通過將它們綁定到動態數據來「創建函數」。當然,沒有人阻止你模仿C語言中的閉包,但有時候這可能是一種痛苦。

關閉是非常有用的。例如,假設我們要實現我們自己的「for循環」:

function loop(count, f) { 
    for (var i = 0; i < count; i++) 
     f(i); 
} 

var array = [0,1,2,3,4]; 

loop(5, function(i) { 
    print(array[i]); 
}); 

被允許訪問外部的變量沒有做一堆額外的廢話保持代碼簡單好用。如果沒有關閉,您可能需要一個上下文變量傳遞給loop函數:

function loop(count, f, ctx) { 
    for (var i = 0; i < count; i++) 
     f(i, ctx); 
} 

var array = [0,1,2,3,4]; 

loop(5, function(i, ctx) { 
    print(ctx[i]); 
}, array); 

又如:假設我們想註冊在jQuery的回調,但它可能長的功能和它的調用者後執行,它的調用者的調用者完成運行:

$(document).ready(function(){ 

    var clicked = 0; 

    $('#button').click(function(){ 
     clicked++; 
     alert("You've pressed the button " + clicked + " times."); 
    }); 

}); 

如果JavaScript的是更喜歡C++(之前的C++ 0x),這clicked變量將由時間長了給$(document).ready()函數被調用,按鈕點擊回調會有未定義的行爲。

+0

有趣的是,C++ 0x現在有一個lambdas,它可以從它們的封閉範圍中捕獲變量。所以*「如果你來自C++背景」*參數變得不那麼重要。 – 2010-07-21 04:29:58

+0

這很酷。謝謝。 – LandonSchropp 2010-07-21 04:35:30

+0

@Alexandre Jasmin - 這些都是非常奇怪的封閉形式。比支持它們的大多數語言更加明確。雖然我其實更喜歡那種方式。我認爲你__應該必須說明你打算從封閉範圍使用哪些變量。 – Omnifarious 2010-07-21 04:56:28

0

如果您想關閉一個例子,我建議你檢查書

深入Python:第六章 - 瓶蓋&發電機

書其開放&免費的,你可以在下載--->http://diveintopython3.org/

這個例子很有趣,很清楚,並逐漸採取了更先進的方法。 對於第一次曝光其偉大的我認爲。

看看它,沒有理由在這裏重現它,只要你可以簡單地下載它或在線閱讀它。