📜  ES6 蹦床函数

📅  最后修改于: 2022-05-13 01:56:14.661000             🧑  作者: Mango

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