在 JavaScript 中为多个值实现记忆模式

Implementing memoize pattern in JavaScript for multiple values

我正在尝试玩一下并使用 JavaScript 为多个值实现记忆模式。 我设法为单值编写了代码:

var lazy = {};
lazy.memoization = evaluator => {
  const cache = new Map;

  return key => {
    cache.has(key) || cache.set(key, evaluator(key));

    return cache.get(key);
  };
};

var memoize = lazy.memoization(key => console.log('computing ', key));
memoize(1); // -> computing 1
memoize(2); // -> computing 2

这是多键版本,它没有按预期工作,它只输出 'computing Array []'、'computing undefined':

var lazy = {};
lazy.memoization = evaluator => {
  const cash = new Map;

  return (...keys) => {
    var values = [];
    keys.reduce((v, f) => {
      if (!cash.has(v)) {
        cash.set(v, evaluator(v));
      }

      values.push(cash.get(v));
    }, values);

    return values;
  };
};

var memoizeMultiple = lazy.memoization((...keys) => {
  keys.forEach(key => console.log('computing ', key))
});
memoizeMultiple(1, 2);

这里有什么问题?

你的代码有很多问题。首先,reducefold的一种,这意味着它通常用于将一个数据结构"collapse"转化为单个值。为了做到这一点,传入 reduce 的函数首先获取 accumulation 值,然后获取数据结构中的每个值。

const sumOf = ns => ns.reduce((sum, num) => sum + num, 0);

sumOf([1, 2, 3, 4, 5]); // -> 15

在此示例中,数据结构是一个 Array,它包含 Number 个值。 reduce 用于将数组中的 所有数字折叠成最终值 (通过将它们相加)。折叠函数称为 reducer 函数(在这个例子中它做加法)。最后,传入reduce的0就是seed的值。

让我们一步步追查到底发生了什么:

在第一次迭代中,reducer 函数被传递了种子值和数组中的第一个数字。因此它看起来像:

(0, 1) => 0 + 1

第二次迭代以第一次迭代的结果作为累加器值和数组中的第二个数字开始:

(1, 2) => 1 + 2

总的来说,它是这样工作的:

(0, 1) => 0 + 1
(1, 2) => 1 + 2
(3, 3) => 3 + 3
(6, 4) => 6 + 4
(10, 5) => 10 + 5

在最后一次迭代之后,reduce returns 是最终的累加器,在这个例子中是 15

好的,回到您提供的代码。您的 "multi arguments memoization" 版本使用 reduce,但 reducer 函数不会 return 中间结果作为新的累加器值,您也不会 return 最终结果 reduce 产生。

另一个问题是您的 evaluator 功能。 returns 的值存储在缓存 Map 实例中。在您的代码中,它 不 return 除了 undefined 之外的任何东西。因此,存储 undefined 并在后续调用记忆函数时 returned。

如果我们解决这些问题,就会奏效:

var lazy = {};
lazy.memoization = evaluator => {
  const cache = new Map();
  return (...args) => {
    return args.reduce((acc, arg) => {
      if (!cache.has(arg)) {
        cache.set(arg, evaluator(arg)); // stores the returned value inside the cache variable
      }

      return acc.concat(cache.get(arg));
    }, []); // the result should be an array, so use that as the seed
  };
};

var memoizeMultiple = lazy.memoization(value => {
  console.log('computing ', value)
  return value; // you have to return something in here, because the return value is stored
});

memoizeMultiple(1, 2);

我希望这能澄清一些事情。编码愉快!