ES6 蹦床函数
在本文中,我们将尝试尽可能详细地了解 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));
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));
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
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
}
}
}
}
}
}
现在如上所示,将进行如此多的函数调用,因此对于较大的输入大小,控制台的输出可能会出现“范围错误:超出最大调用堆栈大小”。
现在为了消除这个错误,图中出现了一个重要的概念,即尾递归(如下所述)。
尾递归:这是一种现象或过程,与常规递归不同,它不是将函数作为操作数传递,而是在下一个递归步骤中传递变化的结果。这一特定过程有助于防止堆栈溢出,但还有一个与之相关的问题,将在本节的后面部分进行描述。
示例:以下代码片段将使事情更加清晰。
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 将以类似的方式处理尾递归因为它处理正常递归,因此在调用堆栈下执行。
蹦床函数:
这个蹦床函数其实就是用来实现尾递归的辅助函数。在此,我们将所有嵌套函数调用转换为函数调用的连续编号,从而帮助我们防止堆栈溢出情况。
trampoline函数基本上将递归函数包装到循环中,因此它进一步调用该递归函数,直到不再存在递归调用。
Trampoline 函数是展示 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