什么是递归
"从前有座山,山里有个庙,庙里有个老和尚在给小和尚讲故事,讲的是从前有座山,山里有个庙,庙里有个老和尚在给小和尚讲故事,讲的是从前有座山。。。"
这就是一个典型的递归,不过这是一个死递归,因为它可以一直进行下去.
如果要把它变成一个常规的递归,就需要给它加一个循环结束的条件:
"从前有座山,山里有个庙,庙里有个老和尚在给小和尚讲故事,讲的是从前有座山,山里有个庙,庙里有个老和尚在给小和尚讲故事,讲的是从前有座山。。。直到有一天地震了,老和尚和小和尚都跑了"
可以得出结论:
常规的递归具有以下两个部分:
1循环体: 老和尚给小和尚讲故事
2循环结束的条件: 地震
这是一个比较通俗的说法,如果用比较专业的说法,那就是:
递归调用是一种特殊的嵌套调用,是某个函数调用自己或者是调用其他函数后再次调用自己的,只要函数之间互相调用能产生循环的则一定是递归调用,递归调用一种解决方案,一种是逻辑思想,将一个大工作分为逐渐减小的小工作.比如说一个和尚要搬50块石头,他想,只要先搬走49块,那剩下的一块就能搬完了,然后考虑那49块,只要先搬走48块,那剩下的一块就能搬完了,递归是一种思想,只不过在程序中,就是依靠函数嵌套这个特性来实现了。
递归执行的过程:
递归的过程简单点说就是在结束条件达成之前,不断地自己调用自己.
而每一次调用,会把函数放进一个先进后出的调用栈中,一个简单的例子是:
打断点之后,每一次往下走,都会把test函数,放进调用栈之中,当我们执行到i=0的时候,这个时候调用栈是最深的有11个test函数,调用栈太深,是很浪费资源的.虽然之后会逐个移除test函数.但是我们可以避免这种情况的.
如何既能起到递归的作用又不会加深调用栈:
这里会用到while循环的思想,调用栈之所以会加深主要是因为方法内调用方法,必须等待方法执行完成这个任务才算是真正的结束,就像A同学有个任务1,这个任务是让B同学完成任务2,在B同学没有完成之前,A同学一直处理工作状态。
那while循环是什么原理呢,可以理解为将有调用关系的方法平铺为同一级别。这需要引入额外的方法来做调度,本来test方法需要调用自己10次的,现在用方法b通过标记的方法来决定是否需要调用test方法
直接上代码:
这个方法的实现步骤是:
利用闭包将f方法保留(这里的f方法就是我们需要递归调用的方法)
创建value、active、accumulated三个变量,并利用了闭包原理避免被垃圾回收
accumulated是保存每次f方法调用后需要传入f的新的形参,active是标记f方法是否执行到了最后一次循环,value是记录需要返回的值
下面的因为tco会return一个新的函数accumulator,所以sum=accumulator,然后再accumulator内只要accumulated长度不为0,while就会一直执行,每次执行sum方法就会accumulated.push(arguments)方法,这样accumulated长度就不会为0。
所以只要f.apply(this, accumulated.shift())执行的时候一旦不调用sum(x + 1, y - 1)方法,accumulated就不会有push操作,这时while就会停止。然后就是active,我们看到if (!active) {...}这个操作,这里保证了只有第一次调用accumulator方法时会进入while循环,剩下的只是起到accumulated.push(arguments)的作用。直到while循环停止,return出来的就是经过n次调用f方法后返回的值了。