错误:acc.concat不是我的js平面数组函数的函数



我正在尝试编写一个js平面函数,如Array.prototype.flat((

使用concat+递归。然而,我的代码总是抛出acc.concat不是函数错误。我不知道我的代码出了什么问题。有人能帮我解决这个问题吗?提前感谢您!

function flatten (arr) {
return arr.reduce((acc, val) => {
if (Array.isArray(val)) {
acc.concat(flatten(val));
} else {
return val;
}
return acc;
}, []);
}

我看到了几个问题:

  • Array#concat不是一个就地函数。它返回一个新的数组,该数组需要分配或返回acc = acc.concat(flatten(val));return acc.concat(flatten(val));
  • val在任何时候都不会被添加到累加器中。return val;打破了回调函数的正常约定,即返回累加器供下一个元素使用

const flatten = a =>
a.reduce((acc, val) =>
acc.concat(Array.isArray(val) ? flatten(val) : val)
, [])
;

console.log(flatten([1,2,3,4,[5,6,[7,[8,9]]]]));

此外,我认为reduce在这里不是最合适的函数。每当我发现我减少到一个数组中而不过滤任何元素时,我知道我可以重构为Array#map,这是一个更具体的reduce。仅当filtermap不易使用时(例如创建对象时(,才首选reduce

const flatten = a =>
[].concat(...a.map(val => Array.isArray(val) ? flatten(val) : val))
;

console.log(flatten([1,2,3,4,[5,6,[7,[8,9]]]]));

这避免了所有相当尴尬的累加器业务。

但是,如果您无法访问排列运算符,并且正在寻求完全兼容性,那么reduce再次很有用,因为它使我们能够在每个元素上调用concat

function flatten(a) {
return a.reduce(function (acc, val) { 
return acc.concat(Array.isArray(val) ? flatten(val) : val);
}, []);
}

console.log(flatten([1,2,3,4,[5,6,[7,[8,9]]]]));

这是因为您在执行递归之前执行了终止递归的步骤,这会让您绊倒。

当您执行if (Array.isArray(val))时,您应该决定是否将val视为一个数组,并再次进入flatten,在这种情况下,您可以继续将其视为正常。然而,在这两种情况下,您都想将val添加到累加器中,但在else分支中,您只需执行return val,因此在下一次执行回调时,acc将等于val,我们已经知道它不是数组。

相反,在这两种情况下,您都应该添加到数组中。唯一的区别是,一次应该递归flatten,另一次不应该。如果终止条件被拉为flatten的一部分而不是reduce回调的一部分,则可以简化:

function flatten (data) {
if(!Array.isArray(data)) return data;

return data.reduce((acc, val) => acc.concat(flatten(val)), []);
}
const input = [[1], [2, [[3]]]];
console.log(flatten(input));

因此,两次都调用flatten,但如果值不是数组,则只需返回它,因此将其视为普通的acc.concat(1)——添加一个普通值。如果你得到了一个数组,那么你就递归地展开并展平它。由于现在flatten不能保证得到一个数组。为了避免混淆,我将参数重命名为data

最新更新