Javascript 递归。为什么以下代码使用 .unshift() 而不是 .push()?

Javascript recursions. Why the following code works with .unshift() instead of .push()?

我的大脑认为我应该使用 .push() 而不是 .unshift() 但 freeCodeCamp 和我的控制台告诉我这是正确的做法。我只是不明白我的数字如何使用 .unshift() 从 10 变为 20,以及使用 .push();

从 20 变为 10

我读代码的方式: 如果 startNum 大于 endNum return 一个空数组。否则,创建一个名为 arr 的变量,并在每次代码运行时将当前 startNum 增加 1 并赋值给它 return 并将其赋值到数组中。

我做错了什么?

function rangeOfNumbers(startNum, endNum) {
  if (startNum > endNum) {
    return [];
  } else {
    const arr = rangeOfNumbers(startNum + 1, endNum);
    arr.unshift(startNum);
    return arr;
  }
}

console.log(rangeOfNumbers(10, 20));

控制台:(11) [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

unshift 将一个元素插入到数组的开头。

由于您是从 startNum 迭代到 endNum,请考虑倒数第二个递归调用:

const arr = rangeOfNumbers(startNum + 1, endNum);
arr.unshift(startNum);
return arr;

其中startNum是19,endNum是20。递归调用returns一个只有一个元素的数组:[20]。然后你需要在适当的位置插入19元素。

为此,您需要在开头插入 19,以获得:

[19, 20]

因此,在 unshift 的开头插入 19。

如果您改用 push,从原来的 [20],您会得到:

[20, 19] // 19 added to end

然后

[20, 19, 18] // 18 added to end

依此类推,顺序不对。

如果在递归调用之前插入元素,则可以使用push

function rangeOfNumbers(startNum, endNum, arr = []) {
  arr.push(startNum);
  if (startNum < endNum) {
    rangeOfNumbers(startNum + 1, endNum, arr);
  }
  return arr;
}

console.log(rangeOfNumbers(10, 20));

一种思考方式是想象递归调用已经正常工作。所以 rangeOfNumbers(11, 20) 会产生 [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]。所以 const arr = rangeOfNumbers(startNum + 1, endNum) 意味着 arr[11, 12, 13, 14, 15, 16, 17, 18, 19, 20]。现在您有 startNumarr 并且需要将它们组合起来。 push 会将 startNum 添加到末尾。 unshift 正确地将其添加到开头。

但既然我们在这里,我想建议一种更优雅的方式来表达相同的算法:

const rangeOfNumbers = (start, end) => 
  start > end 
    ? []
    : [start, ... rangeOfNumbers (start + 1, end)]

我们有一个条件表达式,而不是 if-else 语句。而且我们不会在这个过程中改变像 arr 这样的变量。我认为它也更清晰地表达了算法。当然,口味可能会有所不同,而且,如果您只是学习 JS,这可能涉及您还没有见过的语法。但如果你确实理解它,你可能会同意我对它的优雅的看法。