相信递归函数大家都写过,下面就是个典型的递归函数:
function fibonacci(n) { return n < 2 ? n : fibonacci(n - 2) + fibonacci(n - 1); }
但是像这样的递归函数有个很明显的问题,每次调用的时候都需要重新计算结果,这样过深的递归就会占有过多内存导致堆栈溢出。
针对这种情况,我们可以使用缓存策略来缓存中间的计算值。
var fibonacci = function(){ let cache = {}; return function(n){ if(!cache[n]){ cache[n] = n < 2 ? n : fibonacci(n-2) + fibonacci(n-1); } return cache[n]; } }();
上述方法使用了一个闭包,声明了一个局部变量cache来保存缓存中间的计算值,大家可以在控制台试一下递归层级比较多的时候性能已经得到了很大的提升。
这里解释一下,为什么用的是cache = {},而不是cache = [],是因为cache = {}的性能会更高一些(其实使用场景也会多一些,key不用局限于数字),如果设置了cache = [],在设置cache[100]的时候,目标其实只是想设置一个key为100的value,结果数组会将0-99都会被初始化为empty,而设置对象的话就只会设置key为100的这一项。
这里再包装一层,作为一个用于递归函数的通用缓存函数。
let memoize = function(func) { let cache = {}; return function(key) { if (!cache[key]){ cache[key] = func.apply(this, arguments); } return cache[key]; } } let fibonacci = memoize(function(n) { return n < 2 ? n : fibonacci(n - 2) + fibonacci(n - 1); });
总结:其实原理很简单,就是声明一个变量来缓存中间值,其实看很多框架的源码,都使用了这个方法来提升性能,我们平常在维护自己的组件库或者写业务代码时也可以用上去。