【问题标题】:Memoize implementation using eval. Is this use of eval acceptable?使用 eval 实现记忆。这种使用 eval 可以接受吗?
【发布时间】:2011-09-21 09:57:54
【问题描述】:

...或者有更好的方法来实现记忆?

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");

根据 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);

【问题讨论】:

  • 我看不出比仅传递函数引用有任何优势。另请注意,如果您有具有循环引用的对象,JSON.stringify 将失败。
  • 感谢您的意见。仅供参考:我正在使用 JSON.stringify 的包装器,它使用 replacer 参数来处理循环引用和 DOM 对象的“序列化”。这是必需的,因为参数数组也可以包含具有循环引用的对象。

标签: javascript eval memoization


【解决方案1】:

我认为不需要 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 = {};

【讨论】:

  • TBH 我对您的解决方案不满意,因为我希望将对象定义和记忆分开。我使用 eval 的原因是为了分离,这需要函数的唯一键; callableAsString 就是那个关键。您可能希望使用 Function.toString().hashCode()(java.lang.String.hashCode() 的实现)作为函数的唯一键来查看更新版本。您的建议向我展示了摆脱 eval 的方法。谢谢。
猜你喜欢
  • 2021-10-20
  • 1970-01-01
  • 1970-01-01
  • 2019-09-11
  • 2013-03-05
相关资源
最近更新 更多