--- id: 5cd9a70215d3c4e65518328f title: 使用递归创建一个倒计时 challengeType: 1 forumTopicId: 305925 dashedName: use-recursion-to-create-a-countdown --- # --description-- 在上一个[挑战](/learn/javascript-algorithms-and-data-structures/basic-javascript/replace-loops-using-recursion),学习了怎样用递归来代替循环。现在来学习一个更复杂的函数,函数返回一个从 `1` 到传递给函数的指定数字的连续数字数组。 正如上一个挑战提到的,会有一个 base case。base case 告诉递归函数什么时候不在需要调用其自身。这是简单 情况,返回得到的值。还有 recursive call,继续用不同的参数调用自身。如果函数无误,一直执行直到 base case 为止。 比如,如果想写一个递归函数,返回一个数字 `1` 到 `n` 的连续数组。这个函数需要接收一个参数`n` 代表起始数字。然后会持续的调用自身,传入一个比 `n` 更小的值一直到传入的值是 `1` 为止。函数如下: ```javascript function countup(n) { if (n < 1) { return []; } else { const countArray = countup(n - 1); countArray.push(n); return countArray; } } console.log(countup(5)); // [ 1, 2, 3, 4, 5 ] ``` 起初,这似乎是违反直觉的,因为 n 的值*递减*,但是最终数组中的值却*递增*。 之所以发生这种情况,是因为在递归调用返回之后,才调用 push。 在将 `n` pushed 进数组时,`count(n - 1)` 已经调用赋值成功并返回了 `[1, 2, ..., n - 1]`。 # --instructions-- 已经定义了一个函数 `countdown`,函数有一个参数(`n`)。函数应该基于参数 `n` 递归调用返回 `n` 到 `1` 的连续数字的数组。如果函数以小于 1 的参数调用,函数应该返回空数组。 比如,用 `n = 5` 调用函数应该返回数组 `[5, 4, 3, 2, 1]`。 函数必需使用递归函数调用自身,不能使用任何形式的循环。 # --hints-- `countdown(-1)` 应该返回一个空数组。 ```js assert.isEmpty(countdown(-1)); ``` `countdown(10)` 应该返回 `[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]`。 ```js assert.deepStrictEqual(countdown(10), [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]); ``` `countdown(5)` 应该返回 `[5, 4, 3, 2, 1]`。 ```js assert.deepStrictEqual(countdown(5), [5, 4, 3, 2, 1]); ``` 代码不能包含任意形式的循环(`for`、`while` 或者高阶函数如:`forEach`、`map`、`filter` 以及 `reduce`)。 ```js assert(!removeJSComments(code).match(/for|while|forEach|map|filter|reduce/g)); ``` 应该用递归解决这个问题。 ```js assert(removeJSComments(countdown.toString()).match(/countdown\s*\(.+\)\;/)); ``` # --seed-- ## --seed-contents-- ```js // Only change code below this line function countdown(n){ return; } // Only change code above this line ``` # --solutions-- ```js function countdown(n){ return n < 1 ? [] : [n].concat(countdown(n - 1)); } ```