递归是一种函数式遗产,因此将其与函数式风格一起使用会产生最佳效果。这意味着要避免诸如突变、变量重新分配和其他副作用之类的事情 -
function rangeOfNumbers (startNum, endNum) {
if (startNum > endNum)
return []
else
return [startNum].concat(rangeOfNumbers(startNum + 1, endNum))
}
console.log(JSON.stringify(rangeOfNumbers(0, 3)))
console.log(JSON.stringify(rangeOfNumbers(3, 7)))
console.log(JSON.stringify(rangeOfNumbers(9, 3)))
[0,1,2,3]
[3,4,5,6,7]
[]
使用函数样式意味着您可以将函数调用替换为 return 值,并且总是得到正确的结果。这使您能够对程序进行推理,就好像它们是公式或equations。如果您使用具有命令式风格的递归,那根本不可能 -
rangeOfNumbers(3,6)
== [3].concat(rangeOfNumbers(4,6))
== [3].concat([4].concat(rangeOfNumbers(5,6)))
== [3].concat([4].concat([5].concat(rangeOfNumbers(6,6))))
== [3].concat([4].concat([5].concat([6].concat(rangeOfNumbers(7,6)))))
== [3].concat([4].concat([5].concat([6].concat([]))))
== [3].concat([4].concat([5].concat([6])))
== [3].concat([4].concat([5,6]))
== [3].concat([4,5,6])
== [3,4,5,6]
你可以写出和纯函数表达式一样的东西——
const range = (start, end) =>
start > end
? []
: [start, ...range(start + 1, end)]
console.log(JSON.stringify(range(0, 3)))
console.log(JSON.stringify(range(3, 7)))
console.log(JSON.stringify(range(9, 3)))
[0,1,2,3]
[3,4,5,6,7]
[]
这个可以可视化为-
range(3,6)
== [3, ...range(4, 6)]
== [3, ...[4, ...range(5, 6)]]
== [3, ...[4, ...[5, ...range(6, 6)]]]
== [3, ...[4, ...[5, ...[6, ...range(7, 6)]]]]
== [3, ...[4, ...[5, ...[6, ...[]]]]]
== [3, ...[4, ...[5, ...[6]]]]
== [3, ...[4, ...[5, 6]]]
== [3, ...[4, 5, 6]]
== [3, 4, 5, 6]
只需再增加一个条件,我们也可以支持反向范围 -
const range = (start, end) =>
start > end
? range(end, start).reverse()
: start == end
? [start]
: [start, ...range(start + 1, end)]
console.log(JSON.stringify(range(0, 3)))
console.log(JSON.stringify(range(3, 7)))
console.log(JSON.stringify(range(9, 3)))
[0,1,2,3]
[3,4,5,6,7]
[9,8,7,6,5,4,3] // <- inverse
最后一个可以可视化为 -
range(9,6)
== range(6,9).reverse()
== [6, ...range(7,9)].reverse()
== [6, ...[7, ...range(8,9)]].reverse()
== [6, ...[7, ...[8, ...range(9,9)]]].reverse()
== [6, ...[7, ...[8, ...[9]]]].reverse()
== [6, ...[7, ...[8, 9]]].reverse()
== [6, ...[7, 8, 9]].reverse()
== [6, 7, 8, 9].reverse()
== [9, 8, 7, 6]