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;
}


在这里,我们不预先构造结果数组,而是在堆栈展开时将结果元素(向后!)附加到返回值上。

当然,递归是功能编程的基础。在许多函数式编程语言中,没有其他方法可以循环,只有递归。但这并不意味着递归仍然保留为原始操作:通常,这些语言会基于递归构建其他更复杂的操作,然后使用这些语言代替裸递归来产生很大效果。其中最基本的是mapfilterreduce

了解了递归代码的工作原理后,您可能希望了解如何通过递归实现filter,以及如何在JavaScript中使用更简单的单行代码:

[1,'2','3',2].filter(x => typeof x === "number")
# => [1, 2]

07-24 09:44
查看更多