2011-09-21 49 views
2

...還是有更好的方法來實現一個Memoization?使用eval記憶實現。 eval的使用是否可以接受?

Function.memoize = function(callableAsString) 
    { 
    var r = false, callable, code; 
    try 
     { 
     callable = eval(callableAsString); 
     if (typeof callable == "function" && typeof(Function.memoize.cache[callableAsString]) == "undefined") 
      { 
      code = callableAsString + " = function()" + 
       "{" + 
       "var cache = Function.memoize.cache['" + callableAsString + "'];" + 
       "var k = Json.stringify([this].concat(arguments));" + 
       "return cache.r[k] || (cache.r[k] = cache.c.apply(this, arguments));" + 
       "};" + 
       "true;"; 
      if (r = eval(code)) 
       { 
       Function.memoize.cache[callableAsString] = {c: callable, r: {}}; 
       } 
      } 
     } 
    catch (e) {} 
    return r; 
    }; 
Function.memoize.cache = {}; 
Function.memoize("String.prototype.camelize"); 

更新由費利克斯·克林基礎上,建議

Function.memoize = function(callable) 
    { 
    var r = false; 
    if (typeof callable == "function") 
     { 
     var hash = callable.toString().hashCode(); 
     r = function() 
      { 
      var cache = Function.memoize.cache[hash]; 
      var key = Json.stringify([this].concat(arguments)); 
      return cache.r[key] || (cache.r[key] = cache.c.apply(this, arguments)); 
      } 
     if (!Function.memoize.cache) 
      { 
      Function.memoize.cache = {}; 
      } 
     r.memoize = callable; 
     Function.memoize.cache[hash] = {c: callable, r: {}}; 
     } 
    return r; 
    }; 

Function.unmemoize = function(callable) 
    { 
    if (callable.memoize && typeof callable.memoize == "function") 
     { 
     return callable.memoize; 
     } 
    else 
     { 
     return false; 
     } 
    }; 

String.prototype.camelize = Function.memoize(String.prototype.camelize); 
String.prototype.camelize = Function.unmemoize(String.prototype.camelize); 
+2

我不相比傳遞一個函數引用沒有任何優勢。另請注意,如果您的對象具有循環引用,則'JSON.stringify'失敗。 –

+0

感謝您的輸入。僅供參考:我正在使用JSON.stringify的包裝器,它使用[replacer](https://developer.mozilla.org/En/Using_native_JSON#The_replacer_parameter)參數來處理循環引用和DOM對象的「序列化」。這是必需的,因爲參數數組也可以包含帶有循環引用的對象。 –

回答

0

我不認爲需要EVAL ...考慮這個實施

function memoize(f, cache) 
{ 
    if (!cache) cache = {}; 
    return function() 
    { 
     var key = JSON.stringify(arguments); 
     return (cache[key] || (cache[key] = [f.apply(this, arguments)]))[0]; 
    } 
} 

注意,我故意在密鑰中忽略了this。原因是this可能由於stringify而不能被序列化(例如因爲循環),並且這比例外更規則,例如當在全局上下文中時this == window

什麼是IMO有用的是顯式地傳遞緩存的能力,這樣就可以例如通過執行類似創建爲每個實例或一個共享的緩存所有實例單獨的緩存:

function MyObj(...) 
{ 
    // every instance has its own cache 
    this.foo = memoize(function(...) { ... }); 

    // there is one shared cache for all instances 
    this.bar = memoize(function(...) { ... }, MyObj.memoize_cache); 
} 

MyObj.memoize_cache = {}; 
+0

TBH我不滿意你的解決方案,因爲我希望對象定義和記憶分離。我使用eval的原因是分離,這需要一個獨特的功能鍵; 'callableAsString'是那個關鍵。您可能想使用Function.toString()。hashCode()([java.lang.String.hashCode()]的實現來檢查更新後的版本(http://download.oracle.com/javase/1,5.0/ docs/api/java/lang/String.html#hashCode%28%29))作爲該函數的唯一鍵。 你的建議告訴我擺脫eval的方法。謝謝。 –