问题
...or are there better ways to implement a Memoization?
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");
Update based on the suggestions by Felix Kling
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);
回答1:
I don't see the need for eval... consider this implementation
function memoize(f, cache)
{
if (!cache) cache = {};
return function()
{
var key = JSON.stringify(arguments);
return (cache[key] || (cache[key] = [f.apply(this, arguments)]))[0];
}
}
Note that I deliberately ignored this
in the key. The reason is that this
may not be serializable by stringify
(e.g. because of loops) and this is more the rule than the exception for example when this == window
i.e. in the global context.
What is IMO useful is the ability to explictly pass the cache, so that you can for example create a separate cache for each instance or one shared cache for all instances by doing something like:
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 = {};
来源:https://stackoverflow.com/questions/7497914/memoize-implementation-using-eval-is-this-use-of-eval-acceptable