Javascript中的通用记忆方法

时间:2016-02-12 16:10:44

标签: javascript memoization

据我所知,许多通用的memoized方法依赖于对参数列表进行字符串化并将其用作关键字。例如。如:

Function.prototype.memoized = function() {
    this._values = this.values || {};
    var fn = this;
    return function() {
        var key = JSON.stringify( Array.prototype.slice.call(arguments) );
        if (fn._values[key]===undefined) {
            fn._values[key]=fn.apply(this, arguments);
        }
        return fn._values[key];
    };
};

当人们试图记住“成员函数”时,这显然会失败,因为还必须对上下文进行JSON字符串化,即将其视为隐式传递的参数。但是,当上下文是全局对象或同样深层的东西或者以与函数本身无关的各种方式发生变化时,这种方法就不会很好。

但即使我们坚持使用非“成员函数”,也可能无法始终完成对传递的参数列表的描述,对吗?

三个问题:

  1. 我是否理解正确的记忆成员功能是非感性的?
  2. 我是否理解正确地以一般方式记住非成员函数也是不可能的,因为无法完全字符串化任何可以想象的参数列表?
  3. 如果2成立,那么为什么这么多书和博客试图在Function.prototype中定义一个通用的memoize函数?有什么意义?

1 个答案:

答案 0 :(得分:1)

方法是this作为副作用来源的函数。您可能知道具有副作用的函数无法被记忆,因为这些效果不依赖于memoization依赖的方法参数列表。

但当然有一种解决方法。我们可以手动指定方法所依赖的属性,而不是序列化整个对象(由this引用):

function memoize(f, deps) {
  let cache = {};

  return function(...args) {
    let key = JSON.stringify([deps(), args]), v;
    return cache[key] || (v = f.apply(this, args), cache[key] = v, v);
  };
}

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;

  this.fullName = memoize(
    function(title) { // memoized function
      console.log('memoizing...');
      return title + ' ' + this.firstName + ' ' + this.lastName;
    },
    function() { // dependencies
      return [this.firstName, this.lastName];
    }.bind(this));
}

let person = new Person('Jane', 'Doe');

// initial call
console.log(person.fullName('Ms.')); // memoizing...Ms. Jane Doe

// successive call
console.log(person.fullName('Ms.')); // Ms. Jane Doe

这只是一个概念验证,而不是一个经过全面优化和测试的解决方案。所有功劳都归功于In Lehman's Terms

问题:

  1. 如果一个方法在计算方面非常昂贵,从而证明了工作的合理性,这需要手动定义其隐式依赖关系(this),那么不,它可能是有用的
  2. 是的,有时候这是不可能的,但为什么要完全放弃几乎通用的解决方案?
  3. 说不上!旅鼠? :d