闭包以及递归
在我们平时的工作可能递归用的不是很多,闭包可能我们在不经意间就使用了,所以建议大家有必要的去了解一下。
递归指函数自己调用自己。
当然我们在使用递归时也要注意一些问题:
-
自己调用自己就相当于循环一样,以此来到达一些便利;
-
我们在使用递归时必须要有跳出的条件,不然就会出现死递归;
-
递归在计算的时候会极大的消耗计算机的性能,在计算的值比较小的时候我们可以忽略,当我们使用递归需要循环的值比较大的时候,我们就不得不考虑其的计算效率,那将是一个比较庞大的计算量
下面通过几个例子来给大家讲解一下普通的递归:
1. 求兔子序列(斐波那契数列)的前几项;
var fib = function ( n ) { if ( n === 0 || n === 1 ) return 1; return fib( n - 1 ) + fib( n - 2 ); };
2. 求n^m次方;
function fn(a,b){
if(b==0)return 1;
return fn(a,b-1)*a;
}
3. 求等差数列前几项的和;
function fn(n) {
if (n == 1)return 1;
return fn(n - 1) + (2 * n - 1)
}
在操作递归时,递归会把自己参数中的值进行传递,直到我们传递的值达到我们设置的跳出条件时才会停止传递,而后面的公式指的是与我们需要得到的值进行的相对应操作,当我们写在函数中的值就相当于每一个传递的实参。
但是是递归的性能消耗又是我们不得不重视的,那么下面通过对于数据的缓存来给大家介绍一下如何让递归减少性能的消耗。
、
通过上述的代码我们可以使递归在计算时减少很大一部分的性能消耗。
闭包指的被函数分割而成的作用域,从而形成的被保护的私有数据,这个就被我们称之为闭包。
我们要做的就是通过一些办法来得到闭包内部的数据。
下面给大家讲解一下闭包:
function foo() {
var num = Math.random();
return num;
}
var res = foo();
var r1 = foo();
var r2 = foo();
正常我们觉得从函数中reture出来的值是一样的,当我们打印随机数时,我们会发现值其实是不相同的。只是我们平时在使用闭包的时候,return得到的值是同一个,所以会误认为得到的值是同一个。其实是值不会改变而已。
下面给大家说一下解决的办法:
function func() {
var n = Math.random();
var m = Math.random();
return {
get_N: function () { return n; },
get_M: function () { return m; }
};
}
var o = func();
var n = o.get_N();
var m = o.get_M();
o接收的是在函数func中return出来的对象,所以调用o就是在调用return出来的对象。
所以我们得到的是对象中的函数通过作用域链查找的上一级的值,然后进行保存,只有作用域链被破坏掉时,才会重新获得数据。
下面是通过闭包和递归实现的带有缓存的斐波那契数列
闭包的优点是毋容置疑的,减少对于全局变量的污染,在内部形成一个保护数据的私有空间。我们需要得要数据时必须使用一些特殊的方法才可以访问内部的数据,这样可以很大的保护我们存在于闭包中的数据。
比如我们可以利用沙箱模式来进行处理数据的保护,留下一个特定的方法来可以进行访问,其他方法无效,我们也可以在沙箱中的回调函数中传入document或者dody,window等减少计算机的查询次数。从而减少对于性能的消耗。
(function (w){ function fun() {}; fun.prototype.extend = function (){}; w.I = window.itcast = fun; })(window||document);