3 回答

TA貢獻1789條經驗 獲得超10個贊
簡單的答案:如果str沒有從其他任何地方引用的值(并且str本身也沒有從引用restofprogram),則function (str) { ... }返回時將無法訪問它的值。
詳細說明:V8編譯器區分真正的地方,從所謂的變量范圍內通過封閉拍攝的變量,由陰影與語句來或eval調用。
局部變量存在于堆棧中,并在函數執行完成后立即消失。
上下文變量位于分配給堆的上下文結構中。當上下文結構消失時,它們消失。這里要注意的重要一點是,來自同一作用域的上下文變量位于同一結構中。讓我用示例代碼進行說明:
function outer () {
var x; // real local variable
var y; // context variable, referenced by inner1
var z; // context variable, referenced by inner2
function inner1 () {
// references context
use(y);
}
function inner2 () {
// references context
use(z);
}
function inner3 () { /* I am empty but I still capture context implicitly */ }
return [inner1, inner2, inner3];
}
在這個例子中變量x將盡快消失outer的回報,但變量y,并z只有當將消失兩個 inner1,inner2 和 inner3死。發生這種情況是因為y和z分配在相同的上下文結構中,并且所有三個閉包都隱式引用了此上下文結構(即使inner3沒有顯式使用它)。
當你開始使用情況變得更加復雜與語句來,的try / catch語句來其在V8中包含一個隱含的與語句來里面的catch子句或全局eval。
function complication () {
var x; // context variable
function inner () { /* I am empty but I still capture context implicitly */ }
try { } catch (e) { /* contains implicit with-statement */ }
return inner;
}
在這個例子中,x只有在inner死亡時才會消失。因為:
try / catch-在catch子句中包含 -statement 隱式
V8假定任何帶有 -statement的語句都會遮蓋所有本地人
這迫使x成為上下文變量并inner捕獲上下文,x直到上下文inner消失為止。
通常,如果您要確保給定的變量保留某個對象的時間不超過實際需要的時間,則可以通過分配給該變量輕松地破壞此鏈接null。

TA貢獻1946條經驗 獲得超3個贊
實際上,您的示例有些棘手。是故意的嗎?您似乎在用內部詞法范圍的restofprogram()的參數掩蓋了外部val變量val,而不是實際使用它。但是無論如何,您只是在問一個問題,str因此val,為簡單起見,讓我忽略示例中的棘手問題。
我的猜測是str,即使沒有使用該變量,也不會在restofprogram()函數完成之前收集該變量。如果 restofprogram()不使用str 并且不使用eval(),new Function()那么可以安全地收集它,但我懷疑會這樣做。對于V8來說,這將是一個棘手的優化,可能不值得這樣做。如果沒有eval,并new Function()在語言的話,那就好辦多了。
現在,它不必表示它永遠不會被收集,因為單線程事件循環中的任何事件處理程序都應該立即完成。否則,您的整個過程將被阻塞,并且與內存中一個無用的變量相比,您將面臨更大的問題。
現在,我想知道您的意思不是您在示例中實際寫的。Node中的整個程序就像在瀏覽器中一樣–它只是注冊事件回調,該回調在主程序主體完成后異步觸發。同樣,沒有任何處理程序在阻塞,因此實際上沒有函數花費任何明顯的時間來完成。我不確定我是否理解您在問題中的實際含義,但希望我所寫的內容將有助于您理解所有問題。
更新:
在閱讀了有關程序外觀的注釋中的更多信息之后,我可以說更多。
如果您的程序是這樣的:
readfile("blah", function (str) {
var val = getvaluefromstr(str);
// do something with val
Server.start(function (request) {
// do something
});
});
然后,您也可以這樣寫:
readfile("blah", function (str) {
var val = getvaluefromstr(str);
// do something with val
Server.start(serverCallback);
});
function serverCallback(request) {
// do something
});
這將使strServer.start后走出去的范圍()被調用,并最終將被收集。而且,這將使您的縮進更易于管理,對于更復雜的程序也不要低估它。
至于val您可能會在這種情況下使其成為全局變量,這將大大簡化您的代碼。當然,您不必這樣做,可以與閉包作斗爭,但是在這種情況下,val對于readfile回調和serverCallback函數而言,使global全局化或使其處于外部作用域似乎是最簡單的解決方案。
請記住,在任何地方都可以使用匿名函數時,也可以使用命名函數,對于那些匿名函數,您可以選擇希望它們在哪個作用域中使用。
添加回答
舉報