2015-09-01 116 views
1

當我有一些函數使用其封閉範圍中的變量並在該範圍之外使用該函數(這些範圍)時,這稱爲閉包。它的封閉範圍有多少(javascript)閉包關閉?

是否有關於函數必須關閉的封閉範圍「多少」的任何規範? (?或者,換句話說,在 「怎麼少」 這是絕對需要關閉)

考慮:

function Outer() { 
    var bigGuy = createSomethingHuge(); 
    var tinyNumber = 42; 
    return (function() { /* CONTENTS */ }); 
} 

甚至:

function Layer1() { 
    var bigOne = somethingHugePlease(); 
    var Layer2 = function() { 
    var bigToo = morePlease(); 
    var Layer3 = function() { 
     var huge = reallyHuge(); 
     var tiny = 42; 
     return (function() { /* CONTENTS */ }); 
    }; 
    return Layer3(); 
    }; 
    return Layer2(); 
} 

哪這些變量做最後的返回功能關閉了?它取決於最終功能的內容(eval ...?)嗎?

我最關心的是這些情況是否存在某種規範,而不是關於某些特定實現的行爲。

回答

2

我最感興趣到是否存在某種規範對於這些情況

ECMAScript specification並沒有真正的細節這一點。它只是說一個函數在整個lexical environment關閉,其中包括所有父範圍中的所有變量,以所謂的環境記錄進行組織。但它並沒有指定實現應該如何進行垃圾收集 - 因此引擎必須自己優化它們的閉包 - 當它們可以推斷出某些「閉合」變量從不需要(引用)時,它們通常會這樣做, 。具體來說,如果你確實在封閉的任何地方使用eval,他們當然不能這樣做,並且必須保留一切。

沒有這麼多的一些具體實施的行爲

無論如何,你會想看看How JavaScript closures are garbage collectedgarbage collection with node.jsAbout closure, LexicalEnvironment and GCHow are closures and scopes represented at run time in JavaScript

0

嵌套函數的作用域鏈包含對所有外部函數的激活對象的引用,這些函數的執行導致了嵌套函數的定義。這些激活對象在外部函數調用返回時存儲所有值,並且因爲它們位於作用域鏈中而繼續存在。

因此,根據定義,閉包捕獲範圍內的所有變量值。 eval("typeof bigGuy");'function(){/ * CONTENTS * /}應該證明這一點。

ECMA標準可能*涵蓋了這個(如果你正在編寫一個javascript引擎並且有時間)。當不再需要其值時,可以將大型變量設置爲undefined


*基於10年前閱讀ECMA 3.61。計算機科學術語「封閉」沒有出現在標準中。閉包的產生必須由讀者推斷爲嵌套函數作用域鏈如何構造的一個隱含結果 - 這是標準。範圍鏈包含當前正在執行的函數的激活對象,外部函數的激活對象以相反的順序,隨後是全局對象。範圍鏈不能在用戶代碼中修改。