ES6 缩减了严格模式下尾调用栈的大小,如果满足以下条件,尾调用不再创建新的栈帧,而是清除并重用当前栈帧。
ES6标准入门教程中,有对栈帧通俗的解释。函数调用会在内存中形成一个“调用记录”,又称“调用帧”,保存调用位置和内部变量等信息。如果在函数 A 的内部调用函数 B,那么在 A 的调用帧上方还会形成一个 B 的调用帧。等到 B 运行结束,将结果返回到 A,B 的调用帧才会消失。如果函数 B 内部还调用函数 C,那就还有一个 C 的调用帧,以此类推。所有的调用帧就形成一个“调用栈”。
尾调用不访问当前栈帧的变量(也就是说函数不是一个闭包)。
在函数内部,尾调用是最后一条语句。
尾调用的结果作为函数值返回。
实际上,尾调用的优化发生在引擎背后,除非你尝试优化一个函数,否则无需思考此类问题。递归函数是其最主要的应用场景,此时尾调用优化的效果最显著。
"use strict"
function factorial(n) {
if (n <= 1) {
return 1;
} else {
// 无法优化,因为在返回后执行乘法操作
return n * factorial(n-1);
}
}
"use strict"
function factorial(n, p = 1) {
if (n <=1 ) {
return 1 * p;
} else {
let result = n * p;
// ES6 引擎会进行尾调用优化,如果递归计算量足够大,则尾递归优化可以大幅提升程序的性能。
return factorial(n - 1, result);
}
}