3 回答

TA貢獻(xiàn)1789條經(jīng)驗(yàn) 獲得超10個(gè)贊
簡單的答案:如果str沒有從其他任何地方引用的值(并且str本身也沒有從引用restofprogram),則function (str) { ... }返回時(shí)將無法訪問它的值。
詳細(xì)說明:V8編譯器區(qū)分真正的地方,從所謂的變量范圍內(nèi)通過封閉拍攝的變量,由陰影與語句來或eval調(diào)用。
局部變量存在于堆棧中,并在函數(shù)執(zhí)行完成后立即消失。
上下文變量位于分配給堆的上下文結(jié)構(gòu)中。當(dāng)上下文結(jié)構(gòu)消失時(shí),它們消失。這里要注意的重要一點(diǎn)是,來自同一作用域的上下文變量位于同一結(jié)構(gòu)中。讓我用示例代碼進(jìn)行說明:
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];
}
在這個(gè)例子中變量x將盡快消失outer的回報(bào),但變量y,并z只有當(dāng)將消失兩個(gè) inner1,inner2 和 inner3死。發(fā)生這種情況是因?yàn)閥和z分配在相同的上下文結(jié)構(gòu)中,并且所有三個(gè)閉包都隱式引用了此上下文結(jié)構(gòu)(即使inner3沒有顯式使用它)。
當(dāng)你開始使用情況變得更加復(fù)雜與語句來,的try / catch語句來其在V8中包含一個(gè)隱含的與語句來里面的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;
}
在這個(gè)例子中,x只有在inner死亡時(shí)才會消失。因?yàn)椋?/p>
try / catch-在catch子句中包含 -statement 隱式
V8假定任何帶有 -statement的語句都會遮蓋所有本地人
這迫使x成為上下文變量并inner捕獲上下文,x直到上下文inner消失為止。
通常,如果您要確保給定的變量保留某個(gè)對象的時(shí)間不超過實(shí)際需要的時(shí)間,則可以通過分配給該變量輕松地破壞此鏈接null。

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