最近在刷freeCodeCamp上面的题目,发现了这么一道有趣的题目,加深了我对于js中闭包和立即执行表达式的一些理解,题目如下:
给一个正整数
num
,返回小于或等于num
的斐波纳契奇数之和。斐波纳契数列中的前几个数字是 1、1、2、3、5 和 8,随后的每一个数字都是前两个数字之和。
例如,sumFibs(4)应该返回 5,因为斐波纳契数列中所有小于4的奇数是 1、1、3。
提示:此题不能用递归来实现斐波纳契数列。因为当
num
较大时,内存会溢出,推荐用数组来实现。
第一眼看到这个题目,我就对于他的提示产生了疑惑,为什么不可以用递归,用数组是怎么一回事?看了看他的推荐的资料,我才理解了提示的含义,以下是参考的资料:
1、递归
function Fib(n) {
return n < 2 ? n : (Fib(n - 1) + Fib(n - 2));
}2、数组缓存
var IterMemoFib = function() {
var cache = [1, 1];
return function (n) {
if (n >= cache.length) {
for (var i = cache.length; i < n ; i++ ) {
cache[i] = cache[i - 2] + cache[i - 1];
}
}
return cache[n - 1];
}
}();3、直接使用加法
function fib(n) {
if (n < 2) {
return 1;
}
var a = 1, b = 1;
for (var i = 2; i < n - 1 ;i++ ) {
b = a + b;
a = b - a;
}
return a + b;
}对比:
如果只使用一次运算,第三种方法速度最快;
如果多次使用,第二种方法明显优于其它两种;
在n较大的情况下不推荐使用第一种;n为10*10000的时候递归就已经报内存溢出了
参考的博客地址:http://www.cnblogs.com/meteoric_cry/archive/2010/11/29/1891241.html
以上三种方法都可以用来计算斐波纳契数列,第一种采用的是递归的方法,第二种采用的是数组缓存的技巧,而第三种方法则最为直接的采用一步一步的加法。
但是第二种方法有着其他两种方法都难以超越的优势,即如果要多次使用的话,第二种方法会把之前运算过的结果缓存到cache数组当中,从而大大减少运算量,而且每次运算,第一和第三中方法都要从头开始运算,而第二种方法会先判断结果是否已经计算过了,并且不会从头开始计算,而是从尾部开始计算,而这便运用到了js中的闭包和立即执行函数的功能了。
1 var IterMemoFib = function () { 2 var cache = [1, 1]; 3 4 //下面返回的函数就是一个闭包,其中引用了上一层函数的局部变量cache,这会使的作为局部变量的cache数组常驻内存 5 return function (n) { 6 7 if (n >= cache.length) { 8 for (var i = cache.length; i < n; i++) { 9 cache[i] = cache[i - 2] + cache[i - 1]; 10 } 11 } 12 return cache[n - 1]; 13 } 14 }();
等等,为什么在代码外边套了一个function() {//code here......}();呢?这是干嘛的呢?,其实完全可以这么写:
1 var cache = [1, 1]; 2 function IterMemoFib(n) { 3 if (n >= cache.length) { 4 for (var i = cache.length; i < n; i++) { 5 cache[i] = cache[i - 2] + cache[i - 1]; 6 } 7 } 8 return cache[n - 1]; 9 }
事实证明上述代码也是可以实现的,那么两种方法的区别在于什么地方呢?仔细比较两种方法可以发现,第一种方法只产生了一个全局变量IterMemoFib;然而第二种方法却产生了两个全局变量IterMemoFib和cache,这就是的第一种方法的优点所在。
以上就是我从这道题目中学到的关于闭包和立即执行函数的知识了,下面将这道题目的完整代码贴出供参考:
1 var sumFibs = function () { 2 var cache = [1, 1]; 3 return function (num) { 4 if (num > cache[cache.length - 1]) { 5 var i = cache.length; 6 while (cache[i - 1] < num) { 7 cache[i] = cache[i - 2] + cache[i - 1]; 8 i++; 9 } 10 } 11 var oddArr = cache.filter(function (value, index, arr) { 12 if (value % 2 === 1 && value <= num) { 13 return true; 14 } 15 }); 16 return oddArr.reduce(function (a, b) { 17 return (a + b); 18 }) 19 } 20 }();
由于本人水平有限,以上代码仅供参考。