2011-07-11 47 views
1

我有以下形式的代碼,用戶可以指定一個回調,這將在以後的時間被稱爲:將兩個匿名函數解析爲相同的定義點?

var _deferred = []; 

var deferred = function(callback) { 
    _deferred.push(callback); 
} 

var doDeferred = function() { 
    for(var i = 0, max = _deferred.length; i < max; i++) { 
     _deferred[i].call(); 
    } 
} 

for(var i = 0; i < 5; i++) { 
    deferred(function() { 
     console.log("Some deferred stuff"); 
    }); 
} 

doDeferred(); 

我想認識到指定的遞延()回調是一個匿名函數解決相同的來源,只允許它被添加一次。阿卡在for循環,將拋出一個異常底部當i = 1

像:

var deferred = function(callback) { 
     if(_deferred.indexOf(callback) !== -1) { 
       throw "Already added!"; 
     } 
     _deferred.push(callback); 
} 

我能想到的加入了「鑰匙」這樣做的方法很多,但我想知道如果我可以沿着Function.caller的行來創建一個「源哈希」?

有沒有解決方案已經有,我沒有看到?我真的更願意接受這個負擔,而不是推遲給延遲的調用者,讓他們提供某種獨特的ID。

編輯:

澄清任何混淆。

是的每個延期調用都有一個唯一的函數對象,有自己的閉包等,因此我的indexOf總是失敗。這不是一個混亂點。

問題是,這些匿名函數是在同一個地方聲明的,它們是相同的代碼,我怎麼能確定?我正在尋找確定聲明的平等,而不是實例平等。我想我能以某種方式創建基於遞延呼叫者的哈希...

結論:

謝謝你們,好像也沒有真正優雅的解決方案在這裏。 toString方法不是確定性的(具有相同主體的不同函數將作爲字符串進行測試),並且只是非常難看。我要把這個負擔放在呼叫者身上。

+0

你的'indexOf'方法有什麼問題? 「解決同一來源」究竟是什麼意思? – davin

+0

嗯,它不會拋出異常:) – amirpc

+0

它不會拋出異常,因爲它是內存中的一個不同的函數 – Robert

回答

1

事情是,在底部的循環,他們不同的功能,所以在公平的情況下,他們都應該包括在內(老實說,不能保證這兩個函數的值不會不同取決於當前存在的變量)。我也不確定'唯一功能'是人們所期望的,所以它可能導致大量的「調試」

這不是ECMAScript所要求的,但Function.toString()通常會返回它的內部結構。所以,你可能想:

var ids = [] // separate ID takes up slightly more space, but lookup should 
      // be faster. 
var deferred = function(callback) { 
     var cbs = callback.toString() // or String(callback) 
     if(ids.indexOf(cbs) !== -1) 
     { 
       throw "Already added!"; 
     } 
     ids.push(cbs) 
     _deferred.push(callback); 
} 

如果你願意使用for ... in循環:

var _deferred = {} 
var deferred = function(callback) { 
     var cbs = callback.toString() // or String(callback) 
     if(_deferred[ cbs]) 
     { 
       throw "Already added!"; 
     } 
     _deferred[ cbs] = callback; 
} 

// caution, this executes in arbitrary order. 
var doDeferred = function() { 
    for(var i in _deferred) { 
     _deferred[i].call(); 
    } 
} 
+0

您需要在您的indexOf語句中進行回調,或者將函數與字符串進行比較 – Robert

+0

@Robert ACK!好決定。固定 – cwallenpoole

+0

與此相關的一個問題是,它無法區分對同一個匿名函數的多個調用和閉包。例如如果你有一個像'for(var i = 0; i <5; i ++){deferred((function(j){return function(){console.log(「iteration」+ j)};}(j) )};' - 這仍然被認爲是完全相同的內部(返回)函數減去閉包。我沒有一個更好的建議..雖然它似乎是如果有人想把同一個參考匿名函數作爲重複出於某種目的,可能不想像這樣對待關閉。 –

1

據我所知,如果你有兩個具有相同主體的匿名函數,它們在「==」運算符方面將不等價,所以我認爲你不能執行indexOf()。

您可以檢查您的新功能是否與陣列中已有的功能具有相同的主體。要做到這一點只是將函數轉換爲字符串,並檢查相等性:

String((function(){/*something*/})) == String((function(){/*something*/})) 

應該返回true;

+0

我想說很難定義一個實際的新功能。如果他在每個功能中使用i,那麼即使身體是相同的文本,他們的結果也會不同。您還需要分析範圍對象以真正知道它們是否相同。 – Robert

+0

我不是在尋找真正的平等,只是回調來自代碼中的同一點(即聲明上相同),即使認爲由於範圍等原因,函數實例顯然不相等。 – amirpc

+0

@Robert,是的,它很難決定兩項職能是否與我所建議的相同。但是我認爲他對這些「延遲」函數的作用有一定的控制,所以它可能就足夠了。 – Griffin

1
var deferred = function(callback) { 
    if(_deferred.some(function(c){return c.toString() === callback.toString()})) { 
      throw "Already added!"; 
    } 
    _deferred.push(callback); 
} 

這會在第一次添加重複方法簽名時拋出錯誤。

1

雖然我不會考慮這個優雅,您可以通過使用比較匿名函數他們的toString()方法。

var deferred = function(callback) { 
     var str = callback.toString(); 
     for var i = 0; i < _deferred.length; i++) { 
      if (_deferred[i].toString() == str) { 
       throw "Already added!"; 
      } 
     } 
     _deferred.push(callback); 
} 
相關問題