JS `Array.prototype.flat()` 与 `depth` 参数:控制扁平化深度

各位观众老爷,大家好!今天咱们不聊风花雪月,只谈技术!今天的主题是JavaScript里那个有点像“压路机”的 Array.prototype.flat() 方法,以及它那个控制“压路机”深度的小旋钮:depth 参数。

一、什么是 Array.prototype.flat()

想象一下,你面前有一堆俄罗斯套娃,一个套一个,结构复杂。Array.prototype.flat() 的作用就是把这些套娃拆开,然后把所有的小娃娃(也就是数组里的元素)都摆放到一个桌面上,形成一个扁平的数组。

简单来说,flat() 方法创建一个新数组,其中所有子数组元素都以递归方式连接到该数组中,直到指定的深度。

二、没有 depth 参数的 flat():默认压平一层

如果咱们直接用 flat(),不给它任何参数,它就会默认“压平”一层。就像压路机只压一遍,只把最外层的套娃拆开。

const arr = [1, 2, [3, 4, [5, 6]]];
const flattenedArr = arr.flat();

console.log(flattenedArr); // 输出: [1, 2, 3, 4, [5, 6]]

你看,最外层的那个数组被拆开了,[3, 4, [5, 6]] 里面的 [3, 4] 被拿了出来,但 [5, 6] 仍然保持原样,因为它在更深的一层。

三、depth 参数:控制压平的深度

depth 参数就像压路机上的一个控制旋钮,可以控制压路机压多少遍。它是一个数值,表示要将数组递归扁平化的深度。

  • depth = 1 (默认值): 压平一层,相当于不带参数的 flat()
  • depth = 2: 压平两层。
  • depth = Infinity: 压平所有层,直到数组变成一个完全扁平的数组。

四、depth 参数的用法示例

  1. depth = 2:

    const arr = [1, 2, [3, 4, [5, 6]]];
    const flattenedArr = arr.flat(2);
    
    console.log(flattenedArr); // 输出: [1, 2, 3, 4, 5, 6]

    这次,我们把 depth 设置为 2,压路机压了两遍,成功地把 [5, 6] 也压出来了,得到了一个完全扁平的数组。

  2. depth = Infinity:

    const arr = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]]];
    const flattenedArr = arr.flat(Infinity);
    
    console.log(flattenedArr); // 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    Infinity 简直是压路机的终极形态!不管你的数组有多深,都能给你压成一张薄饼。

  3. depth = 0:

    const arr = [1, 2, [3, 4]];
    const flattenedArr = arr.flat(0);
    
    console.log(flattenedArr); // 输出: [1, 2, [3, 4]]

    depth 为 0 时,相当于什么都没做,返回原数组。压路机原地不动。

五、flat() 处理空槽(empty slots)

flat() 还有一个特性,它可以移除数组中的空槽。 空槽是数组中没有被赋值的位置。

const arr = [1, , 3, [4, , 6]]; // 注意中间的两个逗号,代表空槽
const flattenedArr = arr.flat();

console.log(flattenedArr); // 输出: [1, 3, 4, 6]

看到没?空槽不见了!flat() 就像一个勤劳的清洁工,把数组里的垃圾都清扫干净了。

六、flat() 的使用场景

flat() 在实际开发中有很多用处,比如:

  1. 处理嵌套的数据结构: 从 API 获取的数据可能包含多层嵌套的数组,可以用 flat() 快速扁平化。

  2. 简化代码逻辑: 避免手动编写复杂的递归函数来扁平化数组。

  3. 数据清洗: 移除数组中的空槽,方便后续处理。

七、flatMap()map() + flat() 的组合拳

JavaScript 还有一个 flatMap() 方法,它是 map()flat() 的组合。它首先使用 map() 方法对数组中的每个元素进行处理,然后将结果压平一层。

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

const newArr = arr.flatMap(x => [x * 2]);

console.log(newArr); // 输出: [2, 4, 6, 8]

上面的代码等价于:

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

const mappedArr = arr.map(x => [x * 2]); // [[2], [4], [6], [8]]
const flattenedArr = mappedArr.flat();       // [2, 4, 6, 8]

console.log(flattenedArr);

flatMap() 的一个常见用例是:

const sentences = ["it is a sunny day", "today is wonderful"];

const words = sentences.flatMap(sentence => sentence.split(" "));

console.log(words); // 输出: ["it", "is", "a", "sunny", "day", "today", "is", "wonderful"]

这个例子中,我们首先使用 split() 方法将每个句子分割成单词数组,然后使用 flatMap() 将这些单词数组合并成一个扁平的单词数组。

八、浏览器兼容性

Array.prototype.flat()Array.prototype.flatMap() 是 ES2019 中引入的,所以需要注意浏览器的兼容性。 老版本的浏览器可能不支持这两个方法,需要使用 polyfill 来进行兼容。

你可以使用 Babel 或类似的工具将代码转换为旧版本的 JavaScript,或者使用 MDN 上提供的 polyfill。

九、flat() 的一些注意事项

  1. 性能: 虽然 flat() 很方便,但是对于非常大的嵌套数组,过度使用 flat(Infinity) 可能会影响性能。因为需要递归遍历整个数组。

  2. 内存占用: flat() 会创建一个新的数组,所以需要额外的内存空间。

  3. 循环引用: 如果数组中存在循环引用(例如,一个数组元素指向自身),使用 flat(Infinity) 可能会导致栈溢出。

十、总结

Array.prototype.flat()Array.prototype.flatMap() 是 JavaScript 中非常实用的数组方法。它们可以帮助我们轻松地扁平化嵌套数组,简化代码逻辑,提高开发效率。 depth 参数就像一个精密的旋钮,可以控制压平的深度,满足不同的需求。 但是在使用时也要注意性能、内存占用和循环引用等问题。

十一、flat()flatMap() 的对比表格

特性 flat() flatMap()
功能 扁平化数组 map()flat(),压平一层
参数 depth (可选,默认为 1) callback (必选)
返回值 一个新的扁平化后的数组 一个新的扁平化后的数组
适用场景 简单地扁平化数组 需要对数组元素进行处理后再扁平化
嵌套深度控制 通过 depth 参数控制扁平化深度 只能压平一层
空槽处理 移除空槽 移除空槽
性能 对于深度嵌套的数组,flat(Infinity) 性能可能较差 与先 map()flat() 相比,性能可能略好

十二、代码示例:手写一个简易的 flat() 函数(用于学习理解)

为了更好地理解 flat() 的工作原理,我们可以尝试手写一个简易的 flat() 函数。

function myFlat(arr, depth = 1) {
  const result = [];

  function flatten(arr, currentDepth) {
    for (let i = 0; i < arr.length; i++) {
      const element = arr[i];

      if (Array.isArray(element) && currentDepth < depth) {
        flatten(element, currentDepth + 1); // 递归调用
      } else {
        result.push(element);
      }
    }
  }

  flatten(arr, 0);
  return result;
}

const arr = [1, 2, [3, 4, [5, 6]]];
const flattenedArr = myFlat(arr, 2);

console.log(flattenedArr); // 输出: [1, 2, 3, 4, 5, 6]

这个简易的 myFlat() 函数使用了递归的方式来扁平化数组。 flatten() 函数负责递归遍历数组,如果遇到子数组并且当前的深度小于指定的深度,就继续递归调用自身。 否则,将元素添加到结果数组中。

这个手写的 flat() 函数只是一个简化的版本,没有处理空槽等特殊情况,但是它可以帮助我们更好地理解 flat() 的工作原理。

好了,今天的分享就到这里。希望大家对 Array.prototype.flat()depth 参数有了更深入的了解。 记住,压路机虽好,可不要压坏了花花草草哦! 咱们下期再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注