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的数组。然后它再次调用自己,直到数组为空。
它当前返回一个空数组,调试器显示结果数组保持重置为空数组。
我理解为什么会发生这种情况,但我想弄清楚如何解决这个问题。
答案 0 :(得分:2)
要理解递归,你必须理解递归:)
array.length
为0)
function isNumber(arr) {
// terminate recursion
if (arr.length === 0) return []
// step
var first = arr[0],
rest = arr.slice(1)
// if first is a number concat it with the rest else next step
return typeof first === 'number'? [first].concat(isNumber(rest)) : isNumber(rest)
}
console.log(isNumber([1, '2', '3', 2]));

答案 1 :(得分:1)
结果应该在函数外部创建,因为现在每个函数调用都会创建一个新的空结果并使用新的结果,而不是旧结果,那么你可以检查函数是否正常工作
var result = [];
function isNumber(arr) {
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]);
console.log(result);
如果你想要的话,函数返回一个带有结果的数组,你应该将数组作为函数的参数传递,然后在函数调用后检查它
function isNumber(arr, result) {
if (arr.length > 1) {
if (typeof arr[0] === 'number') {
result.push(arr[0],result);
arr.splice(0, 1);
isNumber(arr);
} else {
arr.splice(0, 1);
isNumber(arr,result);
}
}
}
var result=[];
isNumber([1,'2','3',2], result);
console.log(result);
答案 2 :(得分:1)
您需要存储结果并将其返回。
function isNumber(arr) {
var result = typeof arr[0] === 'number' ? [arr[0]] : [];
arr.shift();
return arr.length ? result.concat(isNumber(arr)) : result;
}
console.log(isNumber([1, '2', '3', 2]));
console.log(isNumber([]));
答案 3 :(得分:1)
你可以用两种不同的方式做到这一点。这个需要随身携带结果数组,但可以进行尾调用优化:
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]
答案 4 :(得分:1)
对代码进行最少的更改:
function isNumber(arr, result) {
if (arr.length > 0) {
if (typeof arr[0] === 'number') {
result.push(arr[0]);
arr.splice(0, 1);
return isNumber(arr, result);
} else {
arr.splice(0, 1);
return isNumber(arr, result);
}
} else {
console.log(result);
}
}
isNumber([1,'2','3',2], []);

答案 5 :(得分:0)
对此事使用递归没有任何意义。如果你真的想这样做,那么下面的例子是一种方法。
每次调用函数时都需要传递结果数组,以便在数组中存储新变量,以便最后返回它。在您当前的示例中,它会一直覆盖变量。
function isNumber(arr, res) {
// If there is no res set, create a new array
var result = res || [];
// Base case, return the result if the arr is empty
if (arr.length <= 0) {
console.log(result);
return result;
}
// Get the first element from the array (and remove it from the array)
var firstElement = arr.shift();
// If it's a number, add it to the array
if (typeof firstElement === 'number') {
result.push(firstElement);
}
isNumber(arr, result);
}
isNumber([1, '2', '3', 2]);
&#13;