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]
。现在您有 startNum
和 arr
并且需要将它们组合起来。 push
会将 startNum
添加到末尾。 unshift
正确地将其添加到开头。
但既然我们在这里,我想建议一种更优雅的方式来表达相同的算法:
const rangeOfNumbers = (start, end) =>
start > end
? []
: [start, ... rangeOfNumbers (start + 1, end)]
我们有一个条件表达式,而不是 if-else
语句。而且我们不会在这个过程中改变像 arr
这样的变量。我认为它也更清晰地表达了算法。当然,口味可能会有所不同,而且,如果您只是学习 JS,这可能涉及您还没有见过的语法。但如果你确实理解它,你可能会同意我对它的优雅的看法。
我的大脑认为我应该使用 .push()
而不是 .unshift()
但 freeCodeCamp 和我的控制台告诉我这是正确的做法。我只是不明白我的数字如何使用 .unshift()
从 10 变为 20,以及使用 .push()
;
我读代码的方式:
如果 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]
。现在您有 startNum
和 arr
并且需要将它们组合起来。 push
会将 startNum
添加到末尾。 unshift
正确地将其添加到开头。
但既然我们在这里,我想建议一种更优雅的方式来表达相同的算法:
const rangeOfNumbers = (start, end) =>
start > end
? []
: [start, ... rangeOfNumbers (start + 1, end)]
我们有一个条件表达式,而不是 if-else
语句。而且我们不会在这个过程中改变像 arr
这样的变量。我认为它也更清晰地表达了算法。当然,口味可能会有所不同,而且,如果您只是学习 JS,这可能涉及您还没有见过的语法。但如果你确实理解它,你可能会同意我对它的优雅的看法。