JavaScript
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
45: Array Methods: flat and flatMap
You’ve probably run into this a dozen times: you fetch some data from an API, and instead of a clean list, you get a list of lists. Maybe it's a list of users, and each user has a list of tags. If you need a unique master list of every tag used across your entire platform, you're suddenly staring at a nested array that doesn't do you any good in its current state.
The struggle with reduce and concat
Before flat() was added to the language, I used to see people (including myself) lean heavily on reduce(). The logic usually looked something like this:
const userTags = [
['javascript', 'webdev'],
['react', 'javascript', 'frontend'],
['node', 'backend']
];
const flattened = userTags.reduce((acc, current) => {
return acc.concat(current);
}, []);
Now, this works. It's logically sound. But it's a bit of a chore to write, and more importantly, it's inefficient. Every time concat() is called, JavaScript creates a brand new array and copies the elements over. If you're dealing with a massive dataset, you're essentially forcing the engine to do a huge amount of unnecessary memory allocation. It's a classic case of "it works on my machine" until the production data hits a certain scale and the performance dips.
Cleaning up the noise with flat
This is exactly why flat() exists. It does one thing: it collapses nested arrays into a new array. No more reduce boilerplate.
const flattened = userTags.flat();
One thing to keep in mind is that flat() only goes one level deep by default. If you've got an array that's nested three or four levels deep—which usually means your data structure is a mess, but it happens—you can pass a depth argument. I've occasionally used flat(Infinity) when I had no idea how deep the nesting went and just wanted everything on one level. Just be careful; flattening a massive, deeply nested structure can be expensive, so use Infinity sparingly.
When mapping and flattening collide
The real magic happens when you need to transform the data and flatten it at the same time. Imagine we have a list of orders, and each order has an array of line items. We want a single list of all the product IDs sold.
The "naive" modern way would be to chain map() and flat():
const orders = [
{ id: 1, items: [{ productId: 'A1' }, { productId: 'B2' }] },
{ id: 2, items: [{ productId: 'C3' }] },
{ id: 3, items: [{ productId: 'A1' }, { productId: 'D4' }] },
];
const productIds = orders.map(order => order.items.map(item => item.productId)).flat();
That works, but it's clunky. You're iterating over the data to map it, creating a nested array, and then iterating over it again to flatten it. This is where flatMap() comes in. It combines both steps into a single pass.
const productIds = orders.flatMap(order =>
order.items.map(item => item.productId)
);
I always reach for flatMap() in this scenario because it's cleaner to read and slightly more performant. It's basically saying: "Transform each element into an array, then flatten the result by one level." It's a powerful pattern, especially when you need to filter items out as well—since flatMap() allows you to return an empty array [] to effectively remove an item from the final result, something a standard map() can't do.
📋 Practical Task
Extracting a Master Playlist from Nested Albums
You are building a music library app. You have an array of album objects, and each album has an array of song objects. Your goal is to create a single, flat array containing only the titles of all songs across all albums, but only for songs that are longer than 3 minutes (180 seconds).
Initial Data:
const library = [
{
album: "Greatest Hits",
songs: [
{ title: "Song A", duration: 200 },
{ title: "Song B", duration: 150 },
]
},
{
album: "Deep Cuts",
songs: [
{ title: "Song C", duration: 210 },
{ title: "Song D", duration: 120 },
{ title: "Song E", duration: 300 },
]
}
];
Your Task: Use flatMap() to generate a flat array of strings (the titles) for all songs that meet the duration criteria. Your final result should be ["Song A", "Song C", "Song E"].
There are no comments for now.