"recursion"、"a non-terminating procedure that happens to refer to itself"、"repeated scheduling"有什么区别?

What are the differences between "recursion", "a non-terminating procedure that happens to refer to itself", and "repeated scheduling"?

此问题旨在作为规范 Question/Answer 来消除关于描述性术语 "recursion" 或 "recursive" 的歧义。在适用范围内,"a non-terminating procedure that happens to refer to itself" 和 "repeated scheduling".


JavaScript

的定义和区别是什么
  1. "recursion";
  2. "a non-terminating procedure that happens to refer to itself";
  3. "repeated scheduling"

我经常看到函数重复调用自身时使用术语 "recursion",尽管 "recursion" 在 JavaScript 中的明确定义是什么?

我很少查看描述函数模式时使用的术语 "a non-terminating procedure that happens to refer to itself" 或 "repeated scheduling";通常 "recursive" 或 "recursion" 用于描述一种模式,在该模式中,在函数调用的主体中,对开始该过程的原始函数进行了函数调用。

什么时候"recursion"不适用于特定的函数模式; "recursion"、"a non-terminating procedure that happens to refer to itself" 和 "repeated scheduling" 之间的明确定义和区别是什么?

递归

I often see the term "recursion" used when a function repeated calls itself, though what is the unambiguous definition of "recursion" in JavaScript?

这个定义看起来没问题,但是函数不必直接调用自己来递归,它的执行只需要导致它被再次调用。函数不直接调用自身的递归示例是:调用 A(); 调用 B();,后者调用 C();,后者再次调用 A();

重复安排

像这样的函数使用重复调度:

function A ( foo ) {
  var bar;
  setTimeout( A, 0 );
  console.log( 'hello' );
}

它不是递归的,因为 A 不会在同一个调用堆栈上重复调用。当当前调用堆栈完成(这意味着 'hello' 将被记录)并且在事件循环中再次调用 A 之前没有其他任何事情,将调用 A。除了同步代码和异步代码之间的区别之外,这里重要的区别是 foobar 一次只有一个副本,并且调用堆栈没有增长,因此会有没有内存或超出最大调用堆栈大小错误,对于使用递归的版本:

function A ( foo ) {
  var bar;
  A();
  console.log( 'hello' );
}

在那种情况下,'hello' 将永远不会被打印,因为 A 在到达日志语句之前会调用自身。

引用自身的非终止过程

非终止过程只是一个无限循环。引用自身有点无意义:

function A ( ) {
    // Never terminates
    while ( true ) {
        // If A() is called here, or before
        // the loop you have infinite 
        // recursion and a stack size error
    }
    // If, instead, A() is called here,
    // you just have an infinite-loop,
    // since this statement is never reached
}