是否考虑了任何自引用功能'递归&#39 ;?

时间:2018-03-05 10:50:18

标签: javascript recursion

关于JavaScript,我可以看到两种不同的编写自引用函数的方法:

Divide和Conquer-like算法,例如阶乘或合并排序,其中值是从不断减小的样本中递归计算的:

const factorialOf20 = (function factorial(n) {
    return (n == 0) ? 1 : n * factorial(n - 1);
})(20);

通过自调用函数循环 (当循环包含异步执行的代码时 - 例如网络请求 - 我发现这很有用但是循环迭代需要被连载)。

var result = '';
(function doLoop(i) {
    if (i < 10) {
        i++;
        request('http://...', function(err, res, body) {
          result += body;
          doLoop(i);
        });
    };
})(0);

在JavaScript中,当通过递归进行循环时,每个函数调用都会设置一个新的执行上下文,并且对于调用不同函数的情况看起来(对我来说)并没有任何不同。

这仍然被认为是递归吗?

3 个答案:

答案 0 :(得分:3)

我想在你的第二个例子中你实际上意味着像

function doLoop() {
   if (hasAsyncWork)
      doAsyncWork({callback: doLoop})
}

所以函数调度自己在稍后的某个时刻运行,而不是直接调用自己。这种模式在javascript中使用很多并且有很多变化,例如:

function fun() {
   do something
   setTimeout(fun, 100)
}

function fun() {
  return doAsyncWork().then(fun)
}

甚至

async function fun(jobs) {
  if (jobs.length)
     await fun(jobs.slice(1))
}

从技术上讲,这不是递归,至少在传统意义上是这样。

答案 1 :(得分:3)

  

这仍然被认为是递归吗?

最终,这更多的是术语和意见,而不是纯粹的技术问题。但是,请考虑以下内容:

function A(num)
{
    if (num < 3) B(num);
}

function B(num)
{
    A(num - 1);
}

也一直被认为是递归; AB都没有直接调用自己,但整个调用链中都有递归。因此,AB都是递归的,因为A仍会导致调用A,同样B

因此,您的示例类似于doLoop未调用doLoop,但它确实会导致doLoop被调用。

如果某些人反对调用此递归,那么doLoop将不会成为之前doLoop的调用链的一部分,或者可能不会(#&} 39;可以编写版本,但不清楚是否立即调用doLoop。这个更具体的递归定义在考虑如何实现语言时(例如,是否存在调用堆栈或其他允许递归的机制)比使用它们的方式更有用。

答案 2 :(得分:2)

也许与georg相反,我认为georg和你的异步示例实际上是传统意义上的递归示例。让我们看一下维基百科中关于递归关系的定义:

...an equation that recursively defines a sequence or 
multidimensional array of values, once one or more
initial terms are given: each further term of the sequence
or array is defined as a function of the preceding terms.

重要的是,异步调用是否定义了一系列值(想想&#34;值&#34;抽象地),每个都来自前一个术语。这一代人是否被延迟甚至是有条件的似乎与我无关。