“尾递归优化”的含义是:如果递归函数属于尾递归,那么运行时会优化其调用过程。优化主要针对调用栈,将多层调用,转化为一层调用。
递归的概念很简单,就是函数调用自身。而所谓的“尾递归”就是在函数体的最后才调用自身。例如:
var fn = function(m, n) {
var x = m + 1
var y = n * 2
fn(x, y)
}
fn(1, 2)
在上述例子中,函数fn在其函数体的最后又调用了自己,fn。这就叫尾递归。
递归调用其实跟普通函数调用并没有本质的不同,都是函数调用函数。但是普通函数调用的层次一般不会太深,这跟设计时的逻辑分层有关。但是递归就不一样了,一不小心就可能产生很多层的调用。试想一下,如果一个递归一直没有返回直接结果,而是一直在调用自身。那么每次调用,函数中的变量、参数都会压栈。由于没有返回,这些栈空间得不到释放,栈很快就会溢出。
当然,设计好的递归调用一般不会产生这样的情形。大多数类似的错误都会在开发阶段发现并解决。比较常见的情形是递归层次较多,栈空间被占用了很多。
而如果是尾递归,由于函数返回的是最后的语句,也就是说返回值只跟最后的调用有关系,那么函数中的变量显然就没有必要保存了。因此针对上述例子,最终可以优化成:
fn(2, 4)