2014-09-26 74 views
0
var state = 0; 
var interval = setInterval(function() { 
    // Do something depending on state 
}, 1000) 

因爲一切都可以在沒有關閉的情況下完成,所以這更像是一個智力活動,因爲我看不到如何在沒有關閉的情況下編程這樣的東西。我是否通過引用將狀態傳遞給匿名函數? (JavaScript不支持通過引用傳遞)如何在沒有關閉的情況下編寫共享狀態?

回答

1

這是一個雙贏的答案,因爲當你仔細考慮它時,絕對沒有範圍不會造成封閉;這是關閉是否被使用以及如何使用的問題。

關閉只是一個內部作用域,它保持對外部作用域的引用。

這樣說吧:

/* global */ 
window.incr_id = 0; 
window.tick = 0; 

function nextTick() { window.tick += 1; } 

window.incr_id = window.setInterval(nextTick, 1000); 

這是否算作封閉,給你?

從技術上講,在全球範圍內有其它語言一個Main()的內部運行的等效,因此nextTick功能保持到外範圍的值(window)的參考,使遍歷了值表的鏈,從而一個「封閉」。

你可以嘗試像

function nextTick() { nextTick.value += 1; } 
nextTick.value = 0; 

...但這是否值得呢,因爲自我參照來自大括號之外,因此屬於更高的範圍?

function nextTick() { arguments.callee.value += 1; } 
nextTick.value = 0; 

當然,這將進而阻止你使用嚴格模式該解決方案(你應該使用它,如果你希望是安全的)。

當然,您可以創建一個閉包,其中不是有問題的函數,而是創建單子,以便您通過組合函數遞增值傳遞值,而不是依賴閉包引用。

那裏的問題當然是setInterval需要一個函數。因此,無論您的函數是否返回setInterval,最終函數都將不得不使用閉包引用,而不管您的所有應用函數是否在先。

如果你引用的函數沒有在你當前的函數範圍內定義,或者我們只是在談論標量,那麼函數引用計數爲閉包引用嗎?

這個故事的寓意:

window.value = 1; 
window.obj.value = 1; 

func.value = 0; 
function func() { func.value = 1; } 

function func() { arguments.callee.value = 1; } 

前兩個是有效的,如果你願意承認,「窗口」,可以爲不封閉引用(提示,它不能)。

如果您願意接受以非嚴格模式運行對您的客戶,觀衆以及您的一般健康和福祉不利的情況,那麼最後一個可能是有效的。

+0

我從這裏得到的結論是,封閉是作爲語言的一部分構建的,無法避免使用它們。我想你不能用JavaScript編寫C風格的代碼。 – allenylzhou 2014-09-26 08:55:49

+0

@allenylzhou我認爲你可以在沒有關閉的情況下進行操作。永遠不要,永遠不要使用函數,或者如果你這樣做,只使用傳遞和變異對象和數組的函數進行開發,因爲對象和數組通過引用傳遞,永遠不會使用異步處理,在某些時候需要對外部範圍進行變量引用。 「關閉」僅僅意味着函數可以讀取其範圍之外的變量;如果你從不在外面引用一個變量,你永遠不會使用*這個功能。但這就像問你是否可以不用指針寫C一樣......當然,忽略他們(/受苦)。 – Norguard 2014-09-26 13:38:59

0

您不需要在JavaScript中通過引用傳遞變量。您通過在關閉中不使用var影響更高層級var

簡單的例子:

var state = 0; 
var interval = setInterval(function(){ 
    state++; // state increases by one every second 
}, 1000); 
// should console.log(4) 
setTimeout(function(){console.log(state)}, 4500); 

如果你這樣做:

var state = 0; 
var interval = setInterval(function(){ 
    var state = 0; 
    state++; // state increases by one every second 
    // state is 1 every time at this point 
    // state outside closure is not affected 
}, 1000); 
// should console.log(0) - state refers to outside of closure 
setTimeout(function(){console.log(state)}, 4500); 

你可以只是覺得在JavaScript中每個變量通過引用,甚至沒有將它們作爲參數,在一定意義上通過。事實上,如果你確實使用變量名作爲參數,它將在你傳遞給它的函數中被重新定義,而不會影響更高級別的變量。

傳遞一個匿名函數的一個參數,根據具體情況可能會或可能不會做任何事情。在setInterval()的情況下,不傳遞任何東西給你傳遞給它的函數。注:

var state = 0; 
var interval = setInterval(function(arg){ 
    var state = 0; 
    state++; // state increases by one every second 
    // state is 1 every time at this point 
    // state outside closure is not affected 
}, 1000); 

相同

var state = 0; 
function what(arg){ 
    var state = 0; 
    state++; // state increases by one every second 
    // state is 1 every time at this point 
    // state outside closure is not affected 
} 
var interval = setInterval(what, 1000); 

所以,真正的函數傳遞到setInterval()不帶任何參數。你輸入function what(){}的任何參數都必須通過setInterval()的參數傳遞,該參數不傳遞這樣的參數。

檢查了這一點:

function whatever(func){ 
    // takes function argument like `setInterval()` 
    // need to pass it something to have func take an argument 
    func("We'll just pass our function this String"); 
} 
whatever(console.log); // now console.log() is passed an argument 

所以,你可以看到,這需要你的函數爲參數的功能決定什麼樣的參數作爲一個參數被傳遞傳遞的功能。

+0

嗯,我想共享狀態(第一個代碼片段),我想知道是否可以在javascript中使用閉包來完成。 – allenylzhou 2014-09-26 01:53:39

1

你可以做所有事情,而無需關閉。例如,可以使用指定方法將狀態存儲在對象中以「調用函數」。但是,您將需要一個不同的setInterval()函數,它接受您的類型的方法,而不是現在需要的函數類型。

0

我是否通過引用將狀態傳遞給匿名函數?

是的。雖然setInterval沒有「關閉」是非常複雜的,因爲它不能讓你通過任何事情。

JavaScript不參照

是支持通過。我們不會使用對變量的引用,而是使用對象來存儲狀態。而不是修改閉包變量,您將修改傳遞的對象。

var state = { 
    value: 0 
}; 
state.interval = setInterval(function() { 
    // Do something depending on this.value 
}.bind(state), 1000); 
相關問題