The answer from Jeremy Thille is great. It explains what's wrong, and gives a useful and understandable alternative. The code is clean and as it's tail-recursive, it can take advantage of tail-call optimization if that ever becomes widespread. There is a bug in it, though: presumably recursive (10, 3)
should return an empty array. Here it will return [10]
.
While we could easily fix that, let's look instead at an alternative which is logically simpler and which avoids the default parameter. (An earlier answer explains some of the potential issues with default parameters. Please understand that they are still a useful and powerful technique, but they do have a downside.)
So here's an alternative version, both in modern syntax:
const range = (from, to) =>
from > to ? [] : [from, ... range (from + 1, to)]
and in an older style:
function range (from, to) {
if (from > to) {
return []
}
return [from] .concat (range (from + 1, to))
}
In either version, we simply recur by creating a new array, starting with the from
value, and then including all the values from the recursive call. We hit a base case when from
is larger than to
and we return an empty array.
There is a big possible eventual disadvantage to this. It's not tail-recursive. Functions in which any recursive call is immediately returned without further processing is called tail-recursive. There are some very useful optimizations on that JS engines can apply to tail-recursive functions to avoid overflowing the recursion stack.
We could make this tail-recursive by adding the default parameter or adding a wrapper function which passes that parameter to an internal recursive helper function. Either would be easy to do. However, we can see that it makes little difference in modern JS, since at the time of this answer almost no engines support proper tail calls, even though I believe doing so is still in the specification. So for now, we won't bother.
Here is this version in action:
const range = (from, to) =>
from > to ? [] : [from, ... range (from + 1, to)]
console .log (range (1, 5)) //=> [1, 2, 3, 4, 5]
console .log (range (4, 4)) //=> [4]
console .log (range (5, 1)) //=> []
.as-console-wrapper {max-height: 100% !important; top: 0}