尾调用
2024年03月12日
一、认识
尾调用Tail Call
指某个函数的最后一步是调用另一个函数。
尾调用函数不会在调用栈上增加新的堆栈帧(不会增加调用栈的长度
),而是直接更新调用栈,调用栈所占空间始终是常量,节省了内存,避免了爆栈的可能性
二、语法
2.1 直接尾调用
function foo1(){
return foo2(); // foo1 函数的最后一步调用另一个函数
}
function foo2(){
console.log("foo2 函数")
}
2.2 三元尾调用
const a = x => x ? f() : g()
// 改写成:
const a = x => {
if (x) {
return f()
} else {
return g()
}
}
可见 f
和 g
的返回值都是直接被返回的,符合尾调用的定义。
2.3 逻辑尾调用
const a = () => f() || g()
// 改写成:
const a = () => {
const result = f()
if (result) {
return result
} else {
return g()
}
}
||
运算符的结果依赖于 f
函数的返回值,而不是直接返回 f
的返回值,直接返回的只有 g
函数的返回值。说明, f
函数也不在尾递归位置上,而 g
函数在尾递归位置上
2.4 逗号尾调用
const a = () => (f(), g())
// 改写成:
const a = () => {
f()
return g()
}
可见,在尾递归位置上的仍然只有一个 g 函数。
2.5 非尾调用语法
-
单独的函数调用不是尾调用
function foo() { bar()}
// 改写成:
function foo() {
bar()
return undefined
}可以看到
return
语句返回的只是一个undefined
而并非bar
函数的返回值,所以这里不存在尾调用。 -
外部函数的最后一步是调用内部的函数并返回
function foo(){
function bar(){
}
return bar();
}函数返回一个内部函数并调用, 不是一个尾调用。