JavaScript函数的特性与应用实践深入详解(8)

15 记忆

有时候可以把先前计算过的结果记录在某个对象中,避免重复计算。

假设我们想通过递归来计算 Fibonacci 数列。一个 Fibonacci 数字是之前的两个 Fibonacci 数字之和,最前面的两个数字是 0 和 1:

var fiboncci = function () {
  var memo = [0, 1];//存储结果(已经计算过的值)
  var fib = function (n) {
    var result = memo[n];
    if (typeof result !== 'number') {
      result = fib(n - 1) + fib(n - 2);
      memo[n] = result;
    }
    return result;
  };
  return fib;
}();
for (var i = 0; i <= 10; i += 1) {
  console.log(i + ": " + fiboncci(i));
}

我们把计算结果存储在 memo 数组中,它被隐藏在闭包里。函数被调用时,它会先检查计算结果是否已存在,如果存在就立即返回。

我们对这个例子进行扩展,构造一个带记忆功能的函数:

/**
 * 带记忆功能的函数
 * @param memo 初始的 memo 数组
 * @param formula 公式函数
 * @returns {Function}
 */
var memoizer = function (memo, formula) {
  var recur = function (n) {
    var result = memo[n];
    if (typeof result != 'number') {
      result = formula(recur, n);
      memo[n] = result;
    }
    return result;
  };
  return recur;
};

这个函数会返回一个可以管理 meno 存储参数和在需要时调用 formula 函数的 recur 函数。recur 函数和它的参数会被传递给 formula 函数(就是公式)。是不是感觉有点绕,我们来看看实例就会清楚啦。

现在我们使用 memoizer 函数来重新定义 fibonacci 函数:

/**
 * 斐波那契
 * @type {Function}
 */
var fibonacci = memoizer([0, 1], function (recur, n) {
  return recur(n - 1) + recur(n - 2);
});
console.log(fibonacci(10));//55

这样清楚了吧,使用这个函数可以极大地减少我们的工作量哦,比如下面的这个阶乘函数:

/**
 * 阶乘
 * @type {Function}
 */
var factorial = memoizer([1, 1], function (recur, n) {
  return n * recur(n - 1);
});
console.log(factorial(10));//3628800

感兴趣的朋友还可以使用本站在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试上述代码运行结果。

更多关于JavaScript相关内容可查看本站专题:《JavaScript常用函数技巧汇总》、《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》及《JavaScript数学运算用法总结》

希望本文所述对大家JavaScript程序设计有所帮助。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/447.html