2011-09-21 57 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的方法。谢谢。 –