你能解释一下这个 freecodecamp 递归函数吗?

Could you explain me this freecodecamp recursion function, please?

这是代码

function rangeOfNumbers(startNum, endNum) {
  return startNum === endNum
    ? [startNum]
    : rangeOfNumbers(startNum, endNum - 1).concat(endNum);
}

我明白直到startNum等于endNum它会自己回忆,但我不明白的是值存储在哪里?

比如说它是 rangeOfNumbers(3,6) 所以它会是这样的:

6-1
5-1
4-1

对吧?每次将数字添加到数组中,我们都会得到 [3,4,5,6],但我不明白它如何以及在哪里存储这个数组。

如果我没记错的话,concat合并了两个或多个数组,但是没有数组。

我只是想对它有一个完整的了解。不然记不住,用不上

一旦满足中断条件 (startNum === endNum),数组就被 returned ([startNum])。这样的对象有一个 concat 函数,它会冒泡到另一个数组等等,直到第一次调用。

在简历中:数组从中断条件开始,endNum 连接到每个 return 值,这也是一个数组。

当输入一个块(以 { 开头并包含语句的东西)时,将创建一个新的 "variable environment"。您可以将其视为将每个标识符 用于该块执行 映射到其值的东西。

每次调用函数时,都会创建一个新的此类环境。

在这种情况下,参数 startNumendNum 存储在第一次调用函数时的环境中。然后,当解释器运行到

rangeOfNumbers(startNum, endNum - 1).concat(endNum);

当前 运行 函数(链接到刚刚描述的环境的函数)被挂起,一个新函数被放入调用堆栈,创建另一个环境。该过程会自行重复,直到到达递归逻辑的末尾并且 [startNum] 被 returned(或堆栈被炸毁)。那时,您有一堆 rangeOfNumbers 函数在进行中,每个函数都有自己的环境。那时,你可以把它想象成

rangeOfNumbers { startNum: 3, endNum: 5 } (this is the intial call; currently suspended)
  rangeOfNumbers { startNum: 4, endNum: 5 } (currently suspended)
    rangeOfNumbers { startNum: 5, endNum: 5 } (executing, about to return)

最里面的函数 return 是它的 [startNum] 并终止,因此最后一个函数恢复,现在具有可用的 return 值:

: rangeOfNumbers(startNum, endNum - 1).concat(endNum);
endNum 为 5 时,

计算为:

: [5].concat(endNum);

这个过程继续堆栈,直到所有的递归调用都完成,你只有初始的

rangeOfNumbers { startNum: 3, endNum: 5 }

然后自行完成。

因此,在进行递归调用时,先前调用的值存储在每个调用的环境中。

If I'm not mistaken, concat merges two or more arrays, but there are no arrays.

[startNum] 是一个数组 returned 在最里面的递归点。 concat 也可以通过将一个数组作为参数并将要追加的值作为另一个数组来创建一个新数组。例如,[5].concat(4) 的计算结果为 [5, 4]

If I'm not mistaken, concat merges two or more arrays, but there are no arrays.

你说的完全正确。 endNum 不是数组。但是,如果您在文档中阅读 further down,则提供给 concat 的参数可以是数组或值。

Parameters

valueN Optional

Arrays and/or values to concatenate into a new array. If all valueN parameters are omitted, concat returns a shallow copy of the existing array on which it is called. See the description below for more details.

Javascript 函数是 variadic 设计的,因此看起来 concat 方法利用这一点接受单独的参数以附加到现有数组的副本。


I understand that until startNum equals endNum it will recall itself, but the thing that I don't understand is where the value is stored?

如果您使用显式变量名编写函数可能会有所帮助

function rangeOfNumbers(startNum, endNum) {
  if (startNum === endNum) {
    return [startNum];
  }
  const currentRange = rangeOfNumbers(startNum, endNum - 1);
  return currentRange.concat(endNum);
}

如您所见,值(或 endNum)存储在通过调用范围 [startNum, endNum - 1].

的函数返回的数组中

关于递归最棘手的部分在于你看不到这些中间值的存储位置,直到我们神奇地到达基本情况,你瞧,我们有一个数组!

答案是rangeOfNumbers(startNum, endNum - 1)返回的数组一直保存在栈内存中,直到需要返回。堆栈与堆的讨论在这里会很离题,但这里几乎涵盖了它:

What and where are the stack and heap?