在 JavaScript 中,递归往往是造成脚本运行缓慢的罪魁祸首。过度的递归会导致浏览器陷入停滞,甚至出现意外退出。因此,递归是一个需要严肃对待的性能问题。在这个系列的《Part2》中,我们简要介绍了如何通过 memoization(记忆化)技术来处理递归过多的情况。Memoization 是一种缓存已经计算过的结果,避免重复计算的技术。在递归函数中,memoization 可以极大地提升性能。
我们在之前讨论的 memoizer 函数主要适用于返回整数的递归函数。但并不是所有的递归函数都返回整数,因此我们可以创建一个更通用的 memoizer
函数来处理任意类型的递归函数:
function memoizer(fundamental, cache){cache = cache || {}var shell = function(arg){if (!cache.hasOwnProperty(arg)){cache[arg] = fundamental(shell, arg)}return cache[arg];};return shell;
}
与 Crockford 的 memoizer 函数相比,这个版本做了一些调整。首先,我们将原始函数作为第一个参数,缓存对象作为可选的第二个参数。并不是所有递归函数都需要初始数据,所以让缓存参数变为可选是合理的。其次,我们将缓存的数据结构从数组改为对象,这样该 memoizer 可以适用于返回非整数结果的递归函数。在 shell
函数内部,我们使用 hasOwnProperty()
方法检查缓存中是否已有对应参数的条目,这比简单检查 undefined
更安全,因为 undefined
也是一种合法的返回值。
示例:优化斐波那契数列的递归计算
通过 memoization,递归计算斐波那契数列的算法可以大幅提升性能。让我们看看使用 memoizer
函数的斐波那契算法:
var fibonacci =