1

我目前正在爲我正在開發的項目構建一個非常簡單的Observer類。我已成功實施了訂閱,取消訂閱和通知方法。當使用「常規」功能(即:var f = function())時,一切都按預期工作。但是,當我將一個匿名函數傳遞給subscribe方法,然後嘗試取消訂閱傳遞「相同」匿名函數時,它(如預期的那樣)不會從我的數組中刪除函數(畢竟他們是不同的) 。Javascript中的匿名函數引用

這裏是我的訂閱和退訂方法

this._subscribers = {}; 
subscribe: function(type, callback) { 
    if (isUndefined(this._subscribers[type])) { 
     this._subscribers[type] = []; 
    } 
    this._subscribers[type].push(callback); 
}, 
unsubscribe: function(type, callback) { 
    if (this._subscribers[type] instanceof Array) { 
     var index = this._subscribers[type].indexOf(callback); 
     if (index >= 0) { 
      this._subscribers[type].splice(index, 1); 
     } 
    } 
}, 

這裏就是我與測試代碼:

var o = new gaf.events.Observable(); 
o.subscribe('testEvent', function(event) { alert('Got It!'); }); 
o.notify('testEvent'); 
// Correct alerts 'Got It!' 
o.unsubscribe('testEvent', function(event) { alert('Got It!'); }); 
o.notify('testEvent') 
// Incorrectly alerts 'Got It!' 

我知道我可以使用一個對象(即:_subscribers [事件] = { }),然後當有東西訂閱我可以添加一個新的屬性等於回調和等於回調的值。這將導致JavaScript將回調轉換爲字符串。然後我可以使用該字符串查找它(假設sub/unsub中傳遞的方法完全相同)。

但是,這是一個移動項目,我非常關心存儲可能長達數百個字符的字符串的屬性,因爲我們可能會收到大量的訂閱者。

還有其他的方法嗎?是否有任何SMALL(小,甚至)哈希庫我可以用來散列函數的字符串值並將其用作屬性?在數組中存儲回調的字符串值(所以我可以比較它)是否更好(而不是實際的回調)並使用eval()?

非常感謝提前!

編輯

首先,感謝所有的答覆!

每所有關於「爲什麼連通匿名」功能的問題 -

實在沒有理由一個人不能使用命名功能。事實上,我同意每個人都認爲命名功能將會是更好的解決方案。我只是收集信息並尋找解決方案,以便我可以構建出儘可能處理大多數情況的實施方案。

這樣做的另一個原因是,如果此Observable類的用戶(同事)將匿名函數傳遞給它並取消訂閱,會發生什麼情況。該功能實際上不會被取消訂閱,因此不會被清理。我有一件事反對孤立的數據:)

也許我應該是另一個問題,是否有可能測試回調是匿名還是不可以?我會假設不,但不會傷害要問。

+1

`eval`是邪惡的。 – SLaks 2011-01-06 13:46:02

+1

作爲一個移動項目,我不認爲你想通過複製匿名函數(一個用於訂閱,一個用於取消訂閱)來浪費空間。此外,您需要哈希庫的開銷(空間和性能)。散列庫需要對函數進行「串化」,然後對其進行散列。 「stringify」操作需要有適當的空格。所有這些聽起來都很讓人頭疼。我建議遵循將函數保存到變量或使用命名函數的最佳做法。 – 2011-01-06 14:30:51

回答

0

也許是更好的解決辦法是使用你的庫

var f = function() { alert('Got It!'); }; 
o.subscribe('testEvent', f); 
o.notify('testEvent'); 
o.unsubscribe('testEvent', f); 
o.notify('testEvent'); 

修改代碼,你甚至可以從訂閱方法返回的功能

var f = o.subscribe('testEvent', function() { alert('Got It!'); }); 
// ... 

那麼,如果你想存儲散列或一些訂閱函數的其他標識符對於調用代碼是不透明的,這意味着您只是使用返回的值來取消訂閱,並且庫隱藏了實現細節。

2

存儲整個字符串沒有任何問題;過早優化是邪惡的。

但是,這聽起來像一個令人難以置信的糟糕主意。
如果有人更改了功能,但忘記更改未訂閱的副本,代碼將被細微地打破,並且不會有任何警告。

相反,如果用戶想取消訂閱,您可以要求用戶將匿名函數存儲在變量中。
或者,您可以爲每個訂閱者傳遞一個可選名稱,然後通過該名稱取消訂閱。

1

使用Observer的客戶端應存儲對函數的引用。

var obsCallback = function() { 

    } 
    o.subscribe('test', obsCallback); 
    .... 
    o.unsubscribe('test', obsCallback); 

換句話說,保持周圍的函數的引用...

0

什麼是傳遞匿名函數,而不是那些命名,或使您可以使用供以後參考退訂的原因?

或者,你可以允許一個可選的'id'參數,但這需要不必要的複雜的簿記以避免重複。