相信很对人对递归函数并不陌生,而滥用递往往容易造成栈溢出。那么有什么好的方法可以避免而同时又保证程序的效率呢?
其实在递归中存在着一种尾递归的形式,尾递归函数的特点是在回归过程中不用做任何操作(只保留一个调用记录),这个特性很重要,因为大多数现代的编译器会利用这种特点自动生成优化的代码。
定义
尾调用的概念非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。尾递归则是调用函数本身。
function f(x){
return g(x);
}
上面代码中,函数f的最后一步是调用函数g,这就叫尾调用。
以下两种情况,都不属于尾调用。
// 情况一
function f(x){
let y = g(x);
return y;
}
// 情况二
function f(x){
return g(x) + 1;
}
上面代码中,情况一是调用函数g之后,还有别的操作,所以不属于尾调用,即使语义完全一样。情况二也属于调用后还有操作,即使写在一行内。
尾调用不一定出现在函数尾部,只要是最后一步操作即可。
function f(x) {
if (x > 0) {
return m(x)
}
return n(x);
}
上面代码中,函数m和n都属于尾调用,因为它们都是函数f的最后一步操作。
参考文章:
尾调用优化