function isNumber(arr) {
var result = [];
if (arr.length > 1) {
if (typeof arr[0] === 'number') {
result.push(arr[0]);
arr.splice(0, 1);
isNumber(arr);
} else {
arr.splice(0, 1);
isNumber(arr);
}
} else {
console.log(result);
}
}
isNumber([1,'2','3',2]);
我正在尝试创建一个通过数组的函数,如果第一项是数字,它将删除它并将其推入名为result的数组。然后,它再次调用自身,直到数组为空。
当前它返回一个空数组,调试器显示结果数组不断重置回一个空数组。
我知道为什么会发生这种情况,但我正在尝试找出解决方法。
最佳答案
您可以通过两种不同的方式来实现。这需要随身携带结果数组,但可以进行尾调用优化:
function onlyNumbers(arr, result) {
if (typeof result === "undefined") result = [];
if (arr.length == 0) return result;
let element = arr.shift();
if (typeof element === "number") {
result.push(element);
}
return onlyNumbers(arr, result);
}
我在这里使用一个技巧来仅在第一个调用中初始化结果数组。在更严格的语言中,我会使用两种不同的功能:一种(非递归)只是为了用
(arr, [])
调用另一种。在第一个循环之后,结果数组随每个调用一起传递,并随每个递归调用一起填充,然后取消调用堆栈,并返回result
,而无需进行任何更改。这种模式的情况恰恰相反(概念上更简单,因为您不需要额外的参数,但无法很好地对其进行优化):
function onlyNumbers(arr) {
if (arr.length == 0) return [];
let element = arr.shift();
let result = onlyNumbers(arr);
if (typeof element === "number") {
result.unshift(element);
}
return result;
}
在这里,我们不预先构造结果数组,而是在堆栈展开时将结果元素(向后!)附加到返回值上。
当然,递归是功能编程的基础。在许多函数式编程语言中,没有其他方法可以循环,只有递归。但这并不意味着递归仍然保留为原始操作:通常,这些语言会基于递归构建其他更复杂的操作,然后使用这些语言代替裸递归来产生很大效果。其中最基本的是
map
,filter
和reduce
。了解了递归代码的工作原理后,您可能希望了解如何通过递归实现
filter
,以及如何在JavaScript中使用更简单的单行代码:[1,'2','3',2].filter(x => typeof x === "number")
# => [1, 2]