3 Array Methods You’re Probably Not Using
Every JavaScript developer knows map, filter, and reduce. These methods show up in every tutorial, every codebase, every interview. But…
3 Array Methods You’re Probably Not Using
Every JavaScript developer knows map, filter, and reduce. These methods show up in every tutorial, every codebase, every interview. But lately, the language has quietly picked up array tools that solve real everyday problems, and some of the code I review still doesn’t use them in places where they may come in handy.
Here are three that have earned a permanent spot in my toolkit as developer; flatMap, at, and Object.groupBy. For each one, I’ll show the old way, the new way, and when to use them.

1. flatMap: map and flatten in one pass
The problem flatMap solves is common, you map over an array, but each item can produce zero, one, or many results. A plain map leaves you with nested arrays that you then have to flatten.
Before:
const orders = [
{ id: 1, items: ['shirt', 'cap'] },
{ id: 2, items: [] },
{ id: 3, items: ['shoes'] },
];
// with just the .map() method
const allItems = orders.map(o => o.items);
// [['shirt', 'cap'], [], ['shoes']]
// with the .flat() method
const allItems = orders.map(o => o.items).flat();
// ['shirt', 'cap', 'shoes']
After:
const allItems = orders.flatMap(o => o.items);
// ['shirt', 'cap', 'shoes']
One method call instead of two, and only one pass over the data instead of building an intermediate nested array first. The less obvious superpower is using flatMap as a map and filter combined. Return an empty array to drop an item, a single-element array to keep it:
const inputs = ['12', 'abc', '7', '', '30'];
const numbers = inputs.flatMap(str => {
const n = parseInt(str, 10);
return Number.isNaN(n) ? [] : [n];
});
// [12, 7, 30]
That would normally take a map followed by a filter, plus the awkwardness of parsing twice or carrying null through the chain. With flatMap it’s one clean step. Reach for it whenever your transformation and your filtering want to happen at the same time, or whenever each input can fan out into multiple outputs.
2. at: clean access from the end of an array
This one is small but I use it constantly. Getting the last item of an array in JavaScript has always been clumsy.
Before:
const pages = ['home', 'about', 'contact'];
const last = pages[pages.length - 1];
// 'contact'
You have to repeat the array name, and if the expression producing the array is long, you either repeat the whole thing or store it in a temporary variable first.
After:
const last = pages.at(-1);
// 'contact'
Negative indices count from the end, so at(-1) is the last item, at(-2) is the second to last, and so on. Positive indices work exactly like bracket notation. Where this really works again is on chained expressions, where the old way forces a variable:
// Before: needs a temporary variable
const parts = url.split('/');
const slug = parts[parts.length - 1];
// After: one line
const slug = url.split('/').at(-1);
You should note that at returns undefined for out-of-range indices, same as bracket access, so your existing guard patterns still apply. You can use this anytime you are about to type an arr[arr.length — 1]. That expression basically shouldn’t exist in your code anymore.
3. Object.groupBy: grouping without reduce boilerplate
Grouping an array into buckets is one of the most common data transformations there is, and for years the standard answer was a reduce that everyone had to squint at.
Before:
const transactions = [
{ type: 'credit', amount: 5000 },
{ type: 'debit', amount: 1200 },
{ type: 'credit', amount: 800 },
];
const grouped = transactions.reduce((acc, t) => {
if (!acc[t.type]) {
acc[t.type] = [];
}
acc[t.type].push(t);
return acc;
}, {});
That’s seven lines to express one idea, and half of it is initialization ceremony.
After:
const grouped = Object.groupBy(transactions, t => t.type);
// {
// credit: [{ type: 'credit', amount: 5000 }, { type: 'credit', amount: 800 }],
// debit: [{ type: 'debit', amount: 1200 }]
// }
I find this one the most interesting. One line. The callback returns the group key for each item, and Object.groupBy handles the bucketing.
The key doesn’t even have to be an existing property either. You can compute it:
const bySize = Object.groupBy(txns, t =>
t.amount >= 1000 ? 'large' : 'small'
);
// { large: [...], small: [...] }
Two practical notes. First, this is a static method on Object, not an array method, so it’s Object.groupBy(arr, fn) rather than arr.groupBy(fn). Second, it landed in ES2024, so check your target environments. It’s supported in all modern browsers and Node 21+, but if you support older targets you’ll want a polyfill or the reduce version. There’s also Map.groupBy if you want a Map back instead of a plain object, which is handy when your keys aren’t strings. You should reach for this method any time you catch yourself writing a reduce whose accumulator is an object of arrays.
The pattern behind all three
Each of these methods replaces a small, repetitive chunk of imperative code with a single expressive call. None of them lets you do anything you couldn’t do before. What they do is remove the boilerplate between your intent and your code, which makes the intent easier to read in review six months later.
Next up on the blog, I’m digging into a JavaScript concept that confused me for far too long: closures, explained the way it finally clicked for me. See you there.
메타데이터
- post_id
- bc155d94020f
- slug
- 3-array-methods-youre-probably-not-using-bc155d94020f
- url
- https://medium.com/@tobilobaolugbemi/3-array-methods-youre-probably-not-using-bc155d94020f
- canonical_url
- https://medium.com/@tobilobaolugbemi/3-array-methods-youre-probably-not-using-bc155d94020f
- author_url
- https://medium.com/@tobilobaolugbemi
- status
- ok
- fetched_at
- 2026-08-19 13:10:02