ES6 Trampoline函数
在本文中,我们将尽可能详细地了解ES6中与Trampoline函数相关的每个方面。让我们首先了解在使用递归时出了什么问题,然后了解尾递归的概念,然后我们将了解为何需要在ES6中引入另一个名为Trampoline函数的函数。
递归出了什么问题?
递归是一种现象或过程,我们通过同一个函数进行多个不同函数调用来计算任何结果值,这些调用由/在栈数据结构中进行管理。递归实际上使代码更简单,并且对于较大的值,实际上将结果逐一解决(也就是逐个值)。
示例:
让我们看下面的代码片段,以便更快而且不高效地理解递归。
Javascript
let sumCalculation = (num) => {
let sum = 0;
return num === 0 ? sum : num + sum + sumCalculation(num - 1);
};
console.log(sumCalculation(5));
console.log(sumCalculation(13));
输出:
15
91
示例: 以下的代码片段展示了上面递归代码的执行。
sumCalculation(5){
sum = 5
sumCalculation(4) {
sum = 5 + 4
sumCalculation(3){
sum = 5 + 4 + 3
sumCalculation(2){
sum = 5 + 4 + 3 + 2
sumCalculation(1){
sum = sum = 5 + 4 + 3 + 2 + 1
sumCalculation(0){
// Returns sum = 15
// Exist all function calls
}
}
}
}
}
}
如上所示,会进行很多函数调用,因此对于较大的输入大小,控制台输出可能会显示“Range Error: Maximum call stack size exceeded”。
为了消除这个错误,一种重要的概念被引入,即尾递归(在下面解释)。
尾递归: 这是一种与常规递归不同的现象或过程,其中我们将下一个递归步骤中的变化结果作为操作数传入,而不是传递一个函数。这个特殊的过程有助于防止堆栈溢出,但也存在一些相关的问题,稍后将在本节的后面部分进行描述。
示例: 以下代码片段将更清楚地说明问题。
Javascript
let sumCalculation = (num) => {
let sumRecursiveCalculation = (result, num) => {
return num === 1 ? result : sumRecursiveCalculation(result + num, num - 1);
};
return sumRecursiveCalculation(1, num);
};
console.log(sumCalculation(5));
console.log(sumCalculation(15));
输出:
15
120
现在存在的问题是JavaScript不认识尾递归,因此即使对于较大的输入,错误仍然是“范围错误:最大调用堆栈大小存在”,因为JavaScript将尾递归视为普通递归,因此在调用堆栈下执行。
平台函数:
这个平台函数实际上是用于实现尾递归的辅助函数。在此过程中,我们将所有嵌套的函数调用转换为顺序的函数调用数量,从而帮助我们避免堆栈溢出的情况。
平台函数基本上将递归函数包装在循环中,并且进一步调用该递归函数,直到不再存在递归调用为止。
尽管平台函数是JavaScript中展示函数式编程的最佳例子。此函数将为我们提供更大值的结果,而以前提到的技术(无论是普通递归还是尾递归)都无法实现。
示例: 下面的代码片段将更清楚地说明这个平台函数的工作原理:
JavaScript
// Trampoline function Implementation
const trampoline_function = (func) => (...rest_arguments) => {
let result = func(...rest_arguments);
while (typeof result === 'function') {
result = result();
}
return result;
};
// Sum Calculation Program Implementation
const sumCalculation = (num, sum = 0) => {
return num === 0 ? sum : () => sumCalculation(num - 1, sum + num);
};
// Wrapping function in Trampoline function
// which is implemented above
const sumCalculate = trampoline_function(sumCalculation);
console.log(sumCalculate(5));
console.log(sumCalculate(1000000));
输出:
15
500000500000