2015-06-03 104 views
1

我已經閱讀了關於閉包和JavaScript上的很多問題,但是我無法找到有關函數在閉合時會發生什麼的信息。通常,這些示例是字符串文本或簡單對象。看下面的例子。當您關閉某個功能時,即使您稍後再進行更改,原始功能也會保留。將JavaScript函數作爲變量關閉時會發生什麼?

什麼在技術上發生在封閉保存的功能?它如何存儲在內存中?它是如何保存的?

請看下面的代碼爲例:

var makeFunc = function() { 
    var fn = document.getElementById; //Preserving this, I will change it later 

    function getOriginal() { 
    return fn; //Closure it in 
    } 

    return getOriginal; 
}; 

var myFunc = makeFunc(); 
var oldGetElementById = myFunc(); //Get my preserved function 

document.getElementById = function() { //Change the original function 
    return "foo" 
}; 

console.log(oldGetElementById.call(document, "myDiv")); //Calls the original! 
console.log(document.getElementById("myDiv")); //Returns "foo" 
+0

變量的類型應該沒有關係;閉包創建時閉包捕獲狀態。有關於您在關閉中保留的函數的參考。然後,您將原件設置爲* new *函數引用;沒有理由閉合應該做任何不同於它爲一個字符串。 –

+0

你並沒有在任何地方改變你的原始功能。 – Nit

+0

@nit see //更改原始功能 – y3sh

回答

1

感謝您的意見和討論。在您的建議後,我發現了以下內容。

保留在閉包中的函數在技術上發生了什麼?

作爲對象的函數被視爲與封閉變量(如字符串或對象)等其他任何簡單對象沒有區別。

它是如何存儲在內存中的?它是如何保存的?

爲了回答這個問題,我不得不挖掘一些關於編程語言的文章。 John C. Mitchell's Concepts in Programming Languages解釋了閉包變量通常在程序堆中結束。

因此,在嵌套子程序中定義的變量可能需要整個程序的生命期,而不僅僅是在其中定義它們的子程序處於活動狀態的時間。據說有一個變量的整個程序的壽命是無限的。這通常意味着它們必須是堆動態的,而不是堆棧動態的。

,較適用於JavaScript的運行時間,Dmitry Soshnikov describes

至於具體實施,用於存儲局部變量的情況下被破壞後,基於堆棧的實現是不適合的話(因爲它違背了定義基於堆棧的結構)。因此,在這種情況下,使用垃圾收集器(GC)和引用計數,將父上下文的封閉數據保存在動態內存分配中(在「堆」中,即基於堆的實現中)。這種系統的速度比基於堆棧的系統效率低。但是,實現可能會始終對其進行優化:在解析階段查找函數中是否使用了自由變量,並根據此決定 - 將數據放入堆棧或「堆」中。

此外,梅德顯示功能關閉豐盛的執行父範圍:

正如我們提到的,優化的目的,當一個函數不使用自由變量,實現可能不保存父範圍鏈。然而,在ECMA-262-3規範中沒有任何關於它的說法;因此,正式(和技術算法) - 所有函數在創建時將範圍鏈保存在[[Scope]]屬性中。

某些實現允許直接訪問封閉範圍。例如在Rhino中,函數的[[Scope]]屬性對應於非標準屬性__parent__。

相關問題