维基百科:尾调用
- 你将会了解到尾调用、尾递归、调用栈。
- 了解尾调用的执行过程及核心原理。
- 明白尾递归的特殊性和实际应用意义。
重点
- ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。
什么是尾调用?(Tail Call)
- 某个函数的最后一步是调用另一个函数,这里的最后一步指正常执行上下文最后一步。
function f(x){
return g(x);
}
- 下面都几种不属于尾调用
function f(x){
let y = g(x);
return y;
}
function f(x){
return g(x) + 1;
}
function f(x){
g(x);
}
尾调用原理
function foo () { console.log(111); }
function bar () { return foo(); }
function baz () { return bar(); }
baz();
解析
- 不熟悉调用栈的,可以学习了解一下。调用栈(call stack)
- 当我们了解到调用栈到原理,你会发现尾调用的诸多限制,都是为了满足调用栈的约束。
-
- 只能在最后一步返回调用,是为了确保没有其他剩下代码需要被执行。
- 只能在严格模式下使用,因为这种行为相当于改变调用栈策略,需要改变语法和执行行为,这种属于破坏性变动。
- 当我们在严格模式下,并保存最后一步返回函数调用,其实相当于告诉调用栈,“你放心,我的代码很安全,你可以开始秀了”。然后调用栈,直接就把上一个函数执行回收了。
什么是尾递归?
- 尾递归是尾调用的一种特殊情况,是指尾调用返回的函数,是自己本身,称为尾递归。
- 可用于优化递归导致的内存问题,从增量内存变成恒量内存(与迭代一样)。
tip
- 尾递归非 javascript 独有,核心是尾调用的调用栈策略。
- 有限递归都可以转换为迭代。
- 递归的本质是压栈,循环中加上栈操作,其实和递归没有本质区别。
- 递归问题用非递归的方式去解,并不会从本质上降低问题层次的深度。
浅谈实际应用
- 个人觉得,业务中,不推荐使用。因为业务的可维护性和稳定性更重要,所以我们尽量不要使用这种需要额外理解成本的操作,并且还会伴随着开发人员后期维护的不确定性。