JS `Array.prototype.flatMap()`:映射并扁平化,提升代码简洁性

各位观众老爷,大家好!今天咱们来聊聊 JavaScript 数组里一个相当实用的家伙——flatMap()。 别看它名字长,其实干的活儿挺简单,就是“映射”和“扁平化”的结合体。 说白了,就是先用一个函数处理数组里的每个元素,然后把处理结果拍扁,变成一个新数组。 听起来有点绕是吧? 没关系,咱们慢慢来,保证你听完之后,也觉得这玩意儿真香!

flatMap()是个啥?

首先,咱们得知道啥是“映射”和“扁平化”。

  • 映射 (Mapping): 就是把数组里的每个元素,通过一个函数,变成另外一个东西。 比如,你可以把一个装着数字的数组,映射成装着这些数字的平方的数组。

  • 扁平化 (Flattening): 就是把一个嵌套的数组(数组里面还有数组),变成一个一维的数组。 比如,[[1, 2], [3, 4]] 扁平化之后就变成了 [1, 2, 3, 4]

flatMap() 呢,就是把这两个操作合二为一。 它先对数组里的每个元素执行一个映射函数,然后把映射结果扁平化成一个新数组。

flatMap() 怎么用?

flatMap() 的语法非常简单:

array.flatMap(function(currentValue, index, array) {
  // 返回处理后的值
}, thisArg)
  • currentValue: 当前正在处理的元素。
  • index: 当前元素的索引。
  • array: 调用 flatMap() 的数组本身。
  • thisArg: (可选) 执行 callback 函数时使用的 this 值。

简单来说,你只需要提供一个函数,告诉 flatMap() 怎么处理数组里的每个元素,它就会帮你把结果拍扁。

举个栗子!

假设我们有一个数组,装着一些句子,每个句子是一个字符串。 我们想把这些句子拆分成单词,然后把所有单词放到一个数组里。 用 flatMap() 可以这样写:

const sentences = ["hello world", "how are you", "good morning"];

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

console.log(words); // 输出: ["hello", "world", "how", "are", "you", "good", "morning"]

这段代码做了什么呢?

  1. sentences.flatMap(...): 我们对 sentences 数组调用 flatMap()
  2. sentence => sentence.split(" "): 这是一个箭头函数,它接收一个句子 (sentence) 作为参数,然后用 split(" ") 方法把句子拆分成单词数组。
  3. flatMap() 会把每个句子拆分出来的单词数组合并成一个一维的数组。

如果没有 flatMap(),你可能需要先用 map() 把句子拆分成单词数组,然后再用 flat() 把结果扁平化。 像这样:

const sentences = ["hello world", "how are you", "good morning"];

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

console.log(words); // 输出: ["hello", "world", "how", "are", "you", "good", "morning"]

看到了吧? flatMap() 可以用一行代码搞定的事情,用 map()flat() 需要两行。 代码更简洁,可读性也更好。

flatMap() 的妙用

flatMap() 除了能简化代码之外,还有一些其他的妙用。

  • 过滤掉某些元素: 你可以利用 flatMap() 的映射功能,在处理元素的同时,过滤掉一些你不想要的元素。 只需要在映射函数里返回一个空数组 []flatMap() 就会自动把这个空数组从结果中移除。

    const numbers = [1, 2, 3, 4, 5];
    
    const evenNumbers = numbers.flatMap(number => {
      if (number % 2 === 0) {
        return [number]; // 返回包含偶数的数组
      } else {
        return []; // 返回空数组,过滤掉奇数
      }
    });
    
    console.log(evenNumbers); // 输出: [2, 4]

    在这个例子中,我们用 flatMap() 过滤掉了奇数,只保留了偶数。

  • 处理嵌套的数据结构: flatMap() 可以方便地处理嵌套的数据结构,比如树形结构。

    const tree = {
      value: 1,
      children: [
        { value: 2, children: [] },
        { value: 3, children: [{ value: 4, children: [] }] }
      ]
    };
    
    function flattenTree(node) {
      return [node.value].concat(node.children.flatMap(flattenTree));
    }
    
    const flattenedTree = flattenTree(tree);
    
    console.log(flattenedTree); // 输出: [1, 2, 3, 4]

    这个例子展示了如何用 flatMap() 递归地扁平化一个树形结构。

flatMap()map().flat() 的区别

虽然 flatMap() 看起来和 map().flat() 很像,但它们之间还是有一些细微的区别的。

  • 性能: 在某些情况下,flatMap() 的性能可能会比 map().flat() 更好。 因为 flatMap() 只需要遍历一次数组,而 map().flat() 需要遍历两次。
  • 可读性: flatMap() 的代码通常更简洁,更容易阅读。
  • 扁平化深度: flatMap() 只能扁平化一层。 如果你需要扁平化多层嵌套的数组,你需要使用 flat(depth) 方法,其中 depth 是扁平化的深度。

flatMap() 的兼容性

flatMap() 是 ES2019 (ES10) 引入的新特性。 这意味着,它在一些比较老的浏览器可能不支持。 如果你需要兼容老版本的浏览器,你可以使用 polyfill 或者使用 map().flat() 来代替。

一些常见的 flatMap() 使用场景

为了让你更好地理解 flatMap() 的用法,这里列举一些常见的使用场景:

使用场景 代码示例 说明
从多个数组中提取元素 javascript const arrays = [[1, 2], [3, 4, 5], [6]]; const numbers = arrays.flatMap(arr => arr); console.log(numbers); // 输出: [1, 2, 3, 4, 5, 6] 将多个子数组合并成一个数组。
转换并过滤数组元素 javascript const numbers = [1, 2, 3, 4, 5]; const doubledEvenNumbers = numbers.flatMap(number => { if (number % 2 === 0) { return [number * 2]; } else { return []; } }); console.log(doubledEvenNumbers); // 输出: [4, 8] 将数组中的偶数翻倍,并过滤掉奇数。
将字符串拆分为字符数组 javascript const strings = ["hello", "world"]; const characters = strings.flatMap(str => str.split("")); console.log(characters); // 输出: ["h", "e", "l", "l", "o", "w", "o", "r", "l", "d"] 将字符串数组转换为字符数组。
处理包含 nullundefined 的数组 javascript const values = [1, null, 2, undefined, 3]; const validValues = values.flatMap(value => value === null || value === undefined ? [] : [value]); console.log(validValues); // 输出: [1, 2, 3] | 过滤掉数组中的 nullundefined 值。
创建重复的数组元素 javascript const numbers = [1, 2, 3]; const repeatedNumbers = numbers.flatMap(number => [number, number]); console.log(repeatedNumbers); // 输出: [1, 1, 2, 2, 3, 3] 将数组中的每个元素重复两次。
映射并展开对象数组 javascript const objects = [{ id: 1, tags: ["a", "b"] }, { id: 2, tags: ["c"] }]; const tags = objects.flatMap(obj => obj.tags.map(tag => ({ id: obj.id, tag }))); console.log(tags); // 输出: [{ id: 1, tag: "a" }, { id: 1, tag: "b" }, { id: 2, tag: "c" }] | 映射对象数组,将每个对象的标签提取出来,并创建一个新的对象数组,其中包含对象的 idtag
异步操作并合并结果 javascript async function fetchData(id) { return new Promise(resolve => setTimeout(() => resolve([id, id * 2]), 100)); } const ids = [1, 2, 3]; async function processIds() { const results = await Promise.all(ids.flatMap(async id => await fetchData(id))); console.log(results); // 输出: [1, 2, 2, 4, 3, 6] } processIds(); | 使用 flatMap 来执行异步操作(例如,从 API 获取数据)并合并结果。 注意:这需要配合 Promise.allasync/await 使用。

总结

flatMap() 是一个非常实用的数组方法,它可以让你用更简洁的代码完成一些复杂的任务。 它可以帮你把映射和扁平化操作合二为一,提高代码的可读性和可维护性。 熟练掌握 flatMap(),可以让你的 JavaScript 代码更加优雅!

好了,今天的 flatMap() 小讲堂就到这里。 感谢各位的观看,希望大家有所收获! 如果有什么疑问,欢迎在评论区留言,咱们一起探讨!

发表回复

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