「JavaScript学习笔记」 尾递归优化

function tail(fn) {
  var value,
    active = false,
    stack = []
  return function() {
    // 接受调用栈参数
    stack.push(arguments)
    
    // 控制被包装的函数开始执行时使用下面的逻辑
    if (!active) {
      active = true
      while (stack.length) {
        // 当fn.apply 执行后,将接受的参数丢给实际要执行逻辑的函数
        // 如果其中还是调用了被优化的具名方法,比如下面的factorial 
        // 那么当执行其中的方法时,由于所有Factorial共享一个active,递归失败,参数传给stack
        // 因此该方法执行时,如果还有factorial执行,则只会把参数都给stack
        // 此时length增加,while循环继续
        value = fn.apply(this, stack.shift())
        // 由此,可以发现只有刚开始调用的方法会循环执行,递归调用的方法,只会把参数传给stack,再拿出来给原始函数调用
        // 最后,当不再调用递归时,while结束
      }
      active = false
      // 返回最后的value
      return value
      // 需要注意的是,如果不是尾调递归,不能这样包装使用
    }
  }
}

// 将实际执行的函数用tail方法包装
var factorial = tail((total, n) => {
  return n === 1
    ? total
    : factorial(n * total, n - 1);
});
factorial(1, 5); // 120


reference

ES6中的尾调优化及其他相关的优化算法

你可能感兴趣的:(「JavaScript学习笔记」 尾递归优化)