【问题标题】:Memoize a prototype method记忆一个原型方法
【发布时间】:2013-05-26 16:53:29
【问题描述】:

我正在尝试使用 memoization 来加速我的 Javascript,但我需要在 proto 方法上使用它,并且我需要所述方法来访问 this 对象,这让我很适应。这是我所拥有的:

MyObj.prototype.myMethod = function(){
    var self = this
        , doGetData = (function() {
            var memo = []
            , data = function(obj) {
                var result = memo;
                if (obj.isDirty) {
                    obj.isDirty = false;
                    result = $.map(obj.details, function(elem, i) {
                        return elem.export();
                    });   
                    memo = result;                      
                }
                return result;
            }
            return data;            
        }())
    ;
    return doGetData(self);
};

我可以让它运行,但我无法让它记忆。我知道出了点问题,但我不知道是什么。我知道有很多关于如何记忆的例子,但我遇到的没有一个像这样处理范围。

【问题讨论】:

  • 你怎么知道它工作不正常?
  • 我一直在做日志检查,当isDirty 为假时,result 是一个空数组,[]isDirty 的初始状态是 true 以强制开始收集数据。

标签: javascript memoization


【解决方案1】:

可以使用 Map 对象来存储和检索所有实例的方法缓存。地图支持对象作为键。 (有点题外话,但严格的模式会影响“this”的传播。现在这可以在没有“var self = this;”的情况下工作。)

"use strict";
MyObj.prototype.myMethod = function() {
    var prototypeCache = new Map();
    return function(arg) {
        if (!prototypeCache.has(this)) prototypeCache.set(this, new Map());
        var instanceCache = prototypeCache.get(this);
        if (instanceCache.has(arg)) return instanceCache.get(arg);
        else {
            //Do expensive calculation that is stored in result...
            instanceCache.set(arg, result);
            return result;
        }                
    };
}();

现在为简单起见,我还为 instanceCache 使用了 Map。对于速度,通常只使用一个对象。这取决于一个人可以制作的钥匙。通常可以找到一种通过唯一字符串进行存储的方法。 (数字可以转换,对象可以有id字符串和状态/版本属性,多个参数可以拼接成一个字符串...)

另一个完全的解决方案是在构造函数中创建方法,而不是在原型中。但这与在实例属性中使用方法缓存一样严重。更糟糕的是,我认为。

【讨论】:

    【解决方案2】:

    如果你想要原型上的函数,但你希望它为每个实例独立记忆,那么“memo”需要是一个实例属性(或者闭包可以是实例属性,我猜;无论哪个)。

    MyObj.prototype.myMethod = function() {
      if (!("memo" in this) || this.isDirty) {
        this.isDirty =false;
        this.memo = $.map(obj.details, function(elem, i) {
           return elem.export();
        });
      }
      return this.memo;
    };
    

    我认为你不能在不污染实例的情况下做到这一点,尽管你可以使用更新的 JavaScript 特性来防止“备忘录”的东西被枚举。毕竟原型是由所有实例共享的。

    【讨论】:

    • @Jason 只有在确保每个实例上都有一个“getData”属性的情况下才会起作用。您不能将每个单独实例的“备忘录”存储为原型对象的“getData”函数的相同属性,除非底层代码使得每个实例的结果始终相同。
    • getData 属性是原型函数,这意味着它应该在每个实例上。我通过this.getData.memo 引用它。这不应该给每个实例一个唯一的值吗?
    • 好吧,我又作弊了.. 我创建了一个this._cache 并将值存储在那里:\ 如果可以防止污染,我想使用 memoization
    • @Jason 问题是,保存每个实例内容的唯一位置是在实例上:/ 您可以使用 Object.defineProperty 确保该属性不会出现在 @987654326 @循环。
    猜你喜欢
    • 1970-01-01
    • 2015-02-17
    • 1970-01-01
    • 1970-01-01
    • 2014-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多