skip to content
Nikolas Barwicki - Javascript Blog Nikolas's Blog

Understanding the .flatMap() method in Javascript

/ 9 min read

Brief Overview of the .flatMap() Method

If you have been creating applications using Javascript or Typescript, dealing with complex arrays or lists would not be an unfamiliar situation. They come with their own unique challenges: performing operations on nested arrays, manipulating data, or trying to access deeply nested elements, to name a few. This is where Javascript’s .flatMap() method shines — a high-level function that operates directly on arrays.

The .flatMap() method, as the name suggests, is a combination of the .flat() and .map() methods. It was introduced in ES2019, an upgrade to the ECMAScript standard, which lays out the specifications of JavaScript.

The .flatMap() method allows you to perform a map operation followed by flat on arrays with a depth of 1. Essentially, it lets you map over an array and flatten the result in one single operation. This can drastically simplify how you handle nested arrays and transform your overall code experience.

Understanding the .flatMap() Method

Basic Syntax of .flatMap()

The syntax of .flatMap() is pretty simple and intuitive:

let newArray = arr.flatMap(function callback(currentValue[, index[, array]]) {
    // return element for newArray
}[, thisArg])

Where:

  • arr is the original array,
  • callback is the function you want to execute for each element in the array. It takes three arguments:
    • currentValue: The current element being processed in the array.
    • index (optional): The index of currentValue being processed.
    • array (optional): The original array arr.
  • thisArg is an optional argument for you to pass the context (this value) to the callback.

This callback function should return the element for newArray. If you wish to map currentValue to multiple elements in the newArray, return them in an array.

How .flatMap() works

Now that we are clear about what .flatMap() is and its syntax let’s understand how it works.

On executing .flatMap(), the callback function runs for each item in the original array. This callback function maps each array item to a new item(s) - a transformation stage reminiscent of the .map() function. This can result in an array of arrays, depending upon what’s returned from the function.

Post the mapping, .flatMap() then comes with its flattening power - similar to what .flat() function does. It flattens the resulting array by one level. Therefore, any single-level nested array gets flatten into a single array.

Please note, .flatMap() only caters to single-level flattening. Any nested arrays which are more than one level deep would stay unflattened.

To sum up, .flatMap() maps and then flattens, all in one method. The added benefit? It does these in one iteration only - therefore providing a performance boost when dealing with large arrays.

In the next section, we’ll dive into some practical use cases of .flatMap() which will help you understand this method better, so stay tuned!

Practical Use Cases of .flatMap()

Exploring some real-world scenarios allows us to better grasp the potential of .flatMap() and understand why it can be a powerful tool in our JavaScript toolkit. In this section, we will delve into three practical use cases: flattening nested arrays, performing mapping and flattening in a single step, and simplifying complex data structures.

Use case 1: Flattening nested arrays

The necessity to flatten nested arrays is a common problem many developers face. This happens when we have an array of arrays, and we want to convert it into a single, flat array.

Consider the following example:

let nestedArray = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
]

In this scenario, if our goal is to convert nestedArray into a flat array like [1, 2, 3, 4, 5, 6, 7, 8, 9], we can use .flatMap() to solve this.

let flatArray = nestedArray.flatMap((arr) => arr)
console.log(flatArray) // Logs: [1, 2, 3, 4, 5, 6, 7, 8, 9]

.flatMap() here is going through each nested array (arr) and returning it. The result is a single, flat array, just as we wanted.

Use case 2: Mapping and flattening in one step

Another situation where .flatMap() proves handy is when we need to perform mapping and flattening simultaneously. Suppose we have an array of strings, and we want to split each string into an array of characters and then flatten it into a single array.

Consider this data:

let strArray = ['hello', 'world']

If we want to end up with a flat array of characters like ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'], .flatMap() offers an elegant solution in one step:

let charArray = strArray.flatMap((str) => str.split(''))
console.log(charArray) // Logs: ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']

By using .flatMap(), we can map each string to an array of its characters using str.split('') and then flatten the result.

Use case 3: Simplifying complex data structures

Finally, .flatMap() can be extremely useful when we need to simplify complex data structures.

For instance, you might have data that includes an array of objects, where each object contains another array. Imagine we have an array of students, and each student has an array of test scores:

let students = [
  { name: 'Alice', scores: [85, 90, 92] },
  { name: 'Bob', scores: [80, 88, 89] },
  { name: 'Charlie', scores: [87, 85, 90] },
]

If we need an array that contains all test scores across all students, we can use .flatMap() to achieve this:

let allScores = students.flatMap((student) => student.scores)
console.log(allScores) // Logs: [85, 90, 92, 80, 88, 89, 87, 85, 90]

In this case, .flatMap() maps each student object to the array of test scores and then flattens the resulting arrays into a single array.

Alternatives to .flatMap()

Using .map() and .flat() separately

Instead of using the handy .flatMap() method, you can also perform mapping and flattening in two separate steps using the .map() and .flat() methods. This can be useful when you wish to keep the steps distinct for easier debugging.

The .map() method creates a new array from the result of calling a function on each element of the original array, while the .flat() method flattens a nested array into a new, one-level deep array.

In comparison to .flatMap(), using .map() and .flat() separately is more verbose as it requires two method calls instead of one. Additionally, it may be less efficient as it iterates twice over the array instead of once.

// array of arrays
let array = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
]

let result = array.map((subArray) => subArray.map((elem) => elem * 2)).flat()

console.log(result) // Output: [2, 4, 6, 8, 10, 12, 14, 16, 18]

Using .reduce() and .concat()

Another alternative to .flatMap() is using a combination of the .reduce() and .concat() methods.

The .reduce() method applies a function against an accumulator and each element in the array to reduce it to a single output value. Meanwhile, .concat() is used to merge two or more arrays.

Just like the previous example, this solution is less straightforward and more verbose than using .flatMap(). However, it has better compatibility across older JavaScript versions.

let array = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
]

let result = array.reduce(
  (acc, subArray) => acc.concat(subArray.map((elem) => elem * 2)),
  []
)

console.log(result) // Output: [2, 4, 6, 8, 10, 12, 14, 16, 18]

Using a loop within a loop

If you prefer staying away from built-in functions, or if you’re working with a particularly complex problem, you can also achieve the same result with a ‘for’ loop nested within another ‘for’ loop.

A loop within a loop is a classic approach to iterate over multi-dimensional arrays. While this method gives you more control over your code, it comes at the cost of readability and simplicity, making the code harder to maintain and debug.

let array = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
]
let result = []

for (let i = 0; i < array.length; i++) {
  for (let j = 0; j < array[i].length; j++) {
    result.push(array[i][j] * 2)
  }
}

console.log(result) // Output: [2, 4, 6, 8, 10, 12, 14, 16, 18]

Advantages of Using .flatMap()

The .flatMap() method has several advantages that make it a robust and practical choice for handling arrays in JavaScript.

Performance Benefits Compared to Alternatives

Compared to other alternative methods, .flatMap() usually delivers better performance. Its internal implementation is optimized, as it executes the map and flat operations in a single iteration. This operational efficiency can considerably reduce the time complexity, particularly when dealing with large arrays. Keep in mind, however, that performance may vary depending on your specific use case and browser.

Code Readability and Maintainability

The .flatMap() method helps improve the readability of your code. By replacing combinations of .map() and .flat(), or nested loops, your code becomes more concise and easier to understand. Less code means fewer potential points of failure, making your code easier to maintain and debug in the long run.

Versatility in Handling Different Data Structures

.flatMap() boasts impressive versatility when it comes to handling different data structures. It can operate across nested arrays of varying depth and types, allowing for more complex manipulations.

Potential Drawbacks and Limitations of .flatMap()

Despite its advantages, .flatMap() is not a silver bullet and it does have some drawbacks and limitations you should be aware of.

Browser Compatibility Issues

One of the primary concerns with .flatMap() is its browser compatibility. While most modern browsers support this method, it is not supported in older versions of Internet Explorer. Therefore, if you are developing for environments where older browsers are still in use, you might want to consider other alternatives or potentially a polyfill.

Limitations with Depth of Flattening

.flatMap() only flattens to a depth of 1. If you have arrays nested deeper than this, you’ll need other methods (like a custom recursive function) or multiple applications of .flatMap().

Not Suitable for All Data Manipulation Scenarios

.flatMap() is a powerful tool, but it’s not suitable for every scenario. For instance, for simple flat maps without nested arrays or when you need to flatten deeper than one level, other methods might be more appropriate.

Conclusion

To sum up, the .flatMap() method is a powerful tool for managing and manipulating arrays in JavaScript. It offers performance benefits over its alternatives and can lead to more readable and maintainable code due to its conciseness. Despite some limitations and compatibility issues, its versatility in handling different data structures adds to its appeal.

I hope this overview has given you a better understanding of .flatMap() and its potential uses in your workflow. Like with all new concepts, practice is key to mastery. Don’t hesitate to experiment with .flatMap() in your own code to explore its features and capabilities. Happy coding!