【问题标题】:Why does [].concat(...arr) help to flatten nested arrays为什么 [].concat(...arr) 有助于展平嵌套数组
【发布时间】:2021-06-02 21:39:23
【问题描述】:

我一个月前才开始学习 javascript。正在阅读 Array.prototype.flat() MDN 以解决问题,但我无法弄清楚为什么该解决方案会以这种方式工作。

他们写了关于扁平化数组的替代方法,并在以下位置使用了 reduce 和 concat:

const arr0 = [1, 2, [3, 4]];

// To flat single level array
const arr1 = arr0.flat();
console.log(arr1) // [1, 2, 3, 4]

// is equivalent to
const arr2 = arr0.reduce((acc, val) => acc.concat(val), []);
console.log(arr2) // [1, 2, 3, 4]

// or with decomposition syntax
const flattened = arr => [].concat(...arr);

const arr3 = flattened(arr0)
console.log(arr3)

通常的acc.concat(val) 对我来说很有意义。我不明白的是分解语法部分。据我了解,当您使用.concat(...arr) 时,扩展运算符会将arr 的所有值传递给.concat 方法,这意味着它应该是[1, 2, [3,4]]。为什么它在返回[1,2,3,4]的过程中居然把1级深嵌套数组展平了?

显然我理解错误。请赐教。

【问题讨论】:

  • 我给你做了一个sn-p。很有用
  • 相当于[].concat(1,2,[3,4])。将数组传递给 concat 会将该数组的内容合并到被调用者中。
  • ...传递非数组只是添加元素本身,这是这里的关键

标签: javascript arrays


【解决方案1】:

首先,这只会展平具有 1 级子数组的数组。如果您的数组有多个级别,例如[1,2,[3,[5,[6]]]],这不会展平整个数组。


在您的语法中,array.concat(another_array) 将数组作为参数传递给调用concat 方法的数组。在这里,another_array 将被添加到 array 中。 concat 将接受多个参数。

let a = [1,2,3], b = [4,5,6], c = [7,8,9];

console.log(a.concat(b,c))
console.log(b.concat(c,a));

concat 不会改变原始数组。

concat 也可以接受单个元素并将其添加到数组中,就像push

例子

let a = [1,2,3];
a = a.concat(4,5,6);
console.log(a)

By 使用扩展语法 ...,您正在解构数组元素并将前 2 个作为单独元素传递,下一个作为数组传递 ((1,2,[3,4]))。

concat 会将其视为 3 个参数,并将其连接到您正在调用该方法的空数组。

【讨论】:

    【解决方案2】:

    通常的 acc.concat(val) 对我来说很有意义。我不明白的是分解语法部分。据我了解,当你使用 .concat(...arr) 时,扩展运算符会将 arr 的所有值传递给 .concat 方法,这意味着它应该是 [1, 2, [3,4] ]。为什么它在返回[1,2,3,4]的过程中居然把1级深嵌套数组展平了?

    几乎正确 - 虽然它不是 [1, 2, [3, 4]](这将再次是一个数组),但它将是一个 1, 2, [3, 4] 的元组。

    fn(1, ...[2, 3, 4], 5)fn(1, 2, 3, 4, 5) 相同。所以在这种情况下,我们正在执行[].concat(...[1, 2, [3, 4]]),它与[].concat(1, 2, [3, 4]) 相同,所以concat 使用三个参数调用:12[3, 4]

    最后一个难题是,concat 对于数组和非数组作为参数的行为不同(请参阅docs):

    concat 方法创建一个新数组,该数组由调用它的对象中的元素组成,然后按顺序为每个参数该参数的元素(如果参数是数组)或参数本身(如果参数不是数组)。它不会递归到嵌套数组参数中。

    这意味着[1, 2].concat(3, [4], 5, [6, 7], 8) 生成一个数组[1, 2, 3, 4, 5, 6, 7, 8],因为参数123[123] 的处理方式相同。 concat 的参数中数组和非数组值之间的这种区别是导致“扁平化效果”的原因,因为这意味着 [].concat(1, 2, [3, 4]) 是有效的并返回 [1, 2, 3, 4]

    通常,concat 与数组一起使用,我自己通常认为x.concat(y, z)[...x, ...y, ...z] 相同(不会导致任何扁平化)但实际上它确实支持非数组参数并处理它们就像它们是数组中唯一的元素一样 - 在我的示例中,它与 [...x, ...Array.isArray(y) ? y : [y], ...Array.isArray(z) ? z : [z]] 相同,实际上与 [...x, ...[y, z].flat()] 相同! - 我还没有看到concat 的非数组参数被大量使用,但它确实有效,这就是[].concat(...arr) 进行单级深度展平的关键原因!

    (顺便说一句,这也适用于reduce 示例。它实际上应该对您同样没有意义!)

    【讨论】:

    • 感谢您的清晰解释,并指出我错在哪里!现在它是有道理的! :D
    【解决方案3】:

    concat 函数可以将number(或其他非数组值)作为参数或其他array(s) 并将这些参数合并到一个数组中。

    这些输入是相同的:

    [].concat(1,2, [3,4]) 等于 [].concat([1], [2], [3,4])

    以下示例可能有助于您理解:

    const test1 = [].concat([3,4])           // [3,4]
    const test2 = [].concat(1)               // [1]
    const test3 = [].concat(1, 2)            // [1, 2]
    const test4 = [].concat(1, 2, [3,4])     // [1,2,3,4]
    const test5 = [].concat([1], [2], [3,4]) // [1,2,3,4]
    const test6 = [].concat(0, [1,2,[3,4]])  // [0,1,2, [3,4]]
    console.log(test6) // it won't flatten deep nested

    【讨论】:

    • 感谢您的解释!看到你输入 [].concat(1,2, [3,4]) 后,我意识到我的误解在哪里。
    猜你喜欢
    • 1970-01-01
    • 2014-05-28
    • 2012-10-31
    • 2017-03-06
    • 2017-07-20
    • 2017-12-26
    • 2019-03-05
    • 1970-01-01
    • 2017-11-06
    相关资源
    最近更新 更多