1. Home
  2. Blog
  3. Software Development

Software Development

JavaScript Array Methods: map, filter, reduce and More With Examples

Stop writing the same loops. Learn the array methods you will use every day on one realistic list of orders, see real output for each, and avoid the traps that catch even experienced developers.

9 min read
JavaScript array methods guide: map, filter, reduce and more with examples

Key takeaways

  • map transforms every item, filter keeps some items, and reduce combines items into one result.
  • These three return new values and leave the original array unchanged.
  • sort changes the original array and compares values as strings by default.
  • Always pass a starting value to reduce, or an empty array throws a TypeError.

Once you know the core JavaScript array methods, most data work becomes a short, readable line rather than a loop with a counter and a temporary variable. They appear everywhere: in React components, API handling and Node scripts alike.

To keep things practical, we use one list of orders throughout, so you can see how methods work together. We ran all of this on Node.js 24, and the outputs shown are from that run. Newer methods such as Object.groupBy need a recent browser or runtime, as noted below.

JavaScript array methods cheat sheet

Method Returns Changes original? Use it to
map New array, same length No Transform each item
filter New array, same or shorter No Keep matching items
reduce Any single value No Sum, count or build objects
find First match or undefined No Get one item
findIndex Position or -1 No Locate one item
some Boolean No Check if any item matches
every Boolean No Check if all items match
sort The same array Yes Order items in place
toSorted New array No Order items safely
flatMap New array No Map, then flatten one level

The sample data

const orders = [
  { id: 1, customer: "Asha", total: 1200, status: "paid" },
  { id: 2, customer: "Ben", total: 300, status: "pending" },
  { id: 3, customer: "Asha", total: 800, status: "paid" },
  { id: 4, customer: "Chitra", total: 2500, status: "paid" },
  { id: 5, customer: "Dev", total: 150, status: "cancelled" },
];

map: transform every item

map calls your function once for each item and collects the return values into a new array. The result always has the same length as the original.

orders.map((o) => o.total);

// [ 1200, 300, 800, 2500, 150 ]

Compare that with the loop it replaces:

const totals = [];
for (const o of orders) {
  totals.push(o.total);
}

The result is identical, but map states the intent straight away, and there is no temporary array to manage. The callback also receives the index as a second argument, and the whole array as a third. That detail causes a famous bug, covered in the mistakes section below.

filter: keep what matches

filter keeps each item for which your function returns a truthy value:

orders.filter((o) => o.status === "paid").map((o) => o.id);

// [ 1, 3, 4 ]

If nothing matches, you get an empty array rather than an error, so code that follows can safely loop over the result.

reduce: combine into one value

reduce confuses people the most, but the idea is simple. It walks through the array carrying a running result, called the accumulator. Your function receives the accumulator and the current item, and returns the next accumulator.

orders.reduce((sum, o) => sum + o.total, 0);

// 4950

Here is how the running value changes on each step:

Step sum before o.total sum after
1 0 1200 1200
2 1200 300 1500
3 1500 800 2300
4 2300 2500 4800
5 4800 150 4950

The accumulator can be any type, not just a number. Start with an empty object, and you can total spending per customer:

const byCustomer = orders.reduce((acc, o) => {
  acc[o.customer] = (acc[o.customer] ?? 0) + o.total;
  return acc;
}, {});

// { Asha: 2000, Ben: 300, Chitra: 2500, Dev: 150 }

Do not forget that return acc. Whatever your function returns becomes the accumulator on the next step, so leaving it out breaks the next iteration.

Chaining methods

Because map and filter return arrays, you can chain them into a readable pipeline. This finds total revenue from paid orders:

const paidTotal = orders
  .filter((o) => o.status === "paid")
  .map((o) => o.total)
  .reduce((sum, t) => sum + t, 0);

// 4500

Filter first, so later steps do less work. Each step creates a new array, which is rarely a problem with ordinary data. If you have a measured performance issue with very large arrays, a single reduce or plain loop can do the same job with fewer allocations. Prefer clarity until you have measured a real problem.

These methods stop as soon as they know the answer, so they are more efficient than filter when you only need one item or a yes or no.

orders.find((o) => o.total > 1000).id;           // 1
orders.findIndex((o) => o.id === 3);             // 2
orders.some((o) => o.status === "cancelled");    // true
orders.every((o) => o.total > 100);              // true

Remember that find returns undefined when nothing matches, so .id on that result would throw. Write orders.find(...)?.id if a match is not guaranteed. To check for a simple value in a list of strings or numbers, includes is shorter: ["paid", "pending"].includes(status).

Tip: If you only need the first match, use find instead of filter(...)[0]. It reads better and stops at the first hit rather than scanning the whole array.

sort and toSorted

sort has two surprises. By default it compares values as strings, and it changes the original array.

[10, 9, 1].sort();                   // [ 1, 10, 9 ]
[10, 9, 1].sort((a, b) => a - b);    // [ 1, 9, 10 ]

As strings, "10" comes before "9", which gives that odd first result. Always pass a compare function for numbers. It should return a negative number if a comes first, or a positive number if b does.

When you need to keep the original order, use toSorted, which returns a new array:

const nums = [3, 1, 2];
nums.toSorted((a, b) => a - b);   // [ 1, 2, 3 ]
nums;                             // [ 3, 1, 2 ]

This is particularly useful in React, where you should not mutate state directly. For older environments, [...nums].sort() achieves the same thing.

flatMap and groupBy

flatMap maps each item and flattens the result by one level, which is handy when one input produces several outputs:

["a b", "c"].flatMap((s) => s.split(" "));

// [ 'a', 'b', 'c' ]

Object.groupBy is a newer built-in that replaces a common reduce pattern. It groups items by a key you return:

const groups = Object.groupBy(orders, (o) => o.status);
Object.keys(groups);

// [ 'paid', 'pending', 'cancelled' ]

It works in current browsers and Node.js 21 or later. Check your support targets before you rely on it.

forEach vs for…of

forEach runs a function for each item but returns nothing, so it suits side effects such as logging. There are two limits to know about: you cannot break out early, and it does not wait for asynchronous callbacks. For sequential async work, use for...of:

for (const order of orders) {
  await saveOrder(order);
}

That runs one at a time. To run them in parallel, use await Promise.all(orders.map(saveOrder)). Our JavaScript async/await guide explains the difference in detail. Callbacks in all these methods are also closures, as explained in JavaScript closures, which is why they can read variables from the surrounding scope.

Common mistakes

Passing parseInt straight to map

["1", "2", "10"].map(parseInt);   // [ 1, NaN, 2 ]
["1", "2", "10"].map(Number);     // [ 1, 2, 10 ]

map passes the item and its index, and parseInt treats that second argument as the number base. So it evaluates parseInt("2", 1), which gives NaN. Use Number or write (s) => parseInt(s, 10).

Calling reduce without a starting value

[].reduce((a, b) => a + b);

// TypeError: Reduce of empty array with no initial value

An API can easily return an empty list, so always provide the initial value.

Forgetting to return from a block

With curly braces, an arrow function needs an explicit return. Writing orders.map((o) => { o.total; }) gives you an array of undefined. Remove the braces or add return.

Mutating objects inside map

map creates a new array, but the objects inside are still the same ones. Writing o.total = 0 in the callback changes your original data. Return a copy instead: orders.map((o) => ({ ...o, total: 0 })).

Final thoughts

Learn map, filter and reduce first, then add find, some and toSorted. Together, they cover most of your day-to-day data handling. To practise, take any loop in your current project and try rewriting it. If the new version reads more clearly, keep it. If it does not, the loop was fine.

Frequently asked questions

What is the difference between map and filter?

map returns a new array of the same length with each item transformed. filter returns a new array containing only the items that pass your test.

What is the difference between map and forEach?

map returns a new array built from your callback’s return values. forEach returns nothing, so use it only for side effects such as logging.

Does map change the original array?

No, it returns a new array. However, if your callback modifies an object inside the array, that original object does change, so return a copy instead.

When should I use reduce?

Use reduce to combine items into one result, such as a total or a lookup object. If a simple map or filter does the job, prefer those for readability.

Why does sort put 10 before 9?

By default, sort compares values as strings, and “10” comes before “9” alphabetically. Pass a compare function such as (a, b) => a – b for numbers.

Keep learning

Work with Stack Quora

Need help with testing, WordPress or SEO?

We help teams ship better software and grow their sites. Tell us what you are working on and we will suggest a clear next step.

Keep reading

More guides on testing, AI & modern development

Enjoyed this article? Pick a topic and jump straight into our newest tutorials.

Artificial Intelligence

LLM Structured Output Explained: Getting Reliable JSON From AI Models

LLM structured output explained with validation we ran in Pydantic: JSON mode and schemas, constrained decoding, the ways model output…

Read article →
DevOps

SSH Keys Explained: How They Work, ssh-keygen, Ed25519 and Safe Habits

SSH keys explained with keys we generated: public vs private keys, ssh-keygen, Ed25519 vs RSA, fingerprints, passphrases, ssh-agent, authorized_keys, config…

Read article →
DevOps

HTTP Caching Explained: Cache-Control, ETag and 304 Responses, With a Live Test

HTTP caching explained with a small server we ran: Cache-Control directives, max-age, no-cache vs no-store, ETag revalidation and 304 responses,…

Read article →
Test Automation

API Contract Testing Explained: Catch Breaking Changes Before They Ship

API contract testing explained with a schema check we ran: what a contract is, consumer-driven contracts, Pact, OpenAPI, which changes…

Read article →
Software Testing

Risk-Based Testing Explained: Score Risks, Build a Matrix and Test What Matters

Risk-based testing explained step by step: identifying risks, scoring likelihood and impact, building a risk matrix, mapping risk to test…

Read article →
Databases & SQL

SQL Constraints Explained: NOT NULL, UNIQUE, CHECK and FOREIGN KEY, Tested

SQL constraints explained with tests we ran: NOT NULL, UNIQUE, CHECK, DEFAULT, PRIMARY and FOREIGN KEY, the NULL loopholes, SQLite's…

Read article →
Databases & SQL

SQL Date Functions Explained: Adding, Comparing and Grouping Dates Without Bugs

SQL date functions explained with queries we ran: adding intervals, month-end surprises, date differences, the BETWEEN trap, grouping by day,…

Read article →
Software Development

Python asyncio Explained: async, await, gather and TaskGroup With Real Timings

Python asyncio explained with code we timed: coroutines, await, gather, TaskGroup, error handling, timeouts, limiting concurrency and the blocking-call mistake…

Read article →
Software Development

Debounce vs Throttle in JavaScript: How They Work, When to Use Each, Tested

Debounce vs throttle in JavaScript explained with timings we measured in Node.js: how each works, simple implementations, leading and trailing…

Read article →
Software Development

Python Context Managers Explained: The with Statement, contextlib and Real Uses

Python context managers explained with code we ran: how with works, __enter__ and __exit__, contextlib.contextmanager, suppress, ExitStack, database transactions and…

Read article →
Artificial Intelligence

LLM Temperature and Top-p Explained: How AI Models Choose Their Next Word

LLM temperature and top-p explained with a simulation we ran: how probabilities are reshaped, what top-p keeps, recommended settings by…

Read article →
DevOps

YAML Explained: Syntax, the Norway Problem and Other Traps We Tested

YAML explained with a parser test: basic syntax, lists and maps, the Norway problem, versions turning into floats, octal zip…

Read article →
DevOps

Cron Jobs Explained: Syntax, Real Schedules and the Mistakes That Break Them

Cron jobs explained with schedules we verified: the five fields, operators, real examples, the day-of-month OR day-of-week trap, environment problems,…

Read article →
Software Testing

Bug Life Cycle in Software Testing: Every Status, Who Owns It and Common Mistakes

The bug life cycle explained: every defect status from New to Closed, who owns each step, rejected, deferred and reopened…

Read article →
Test Automation

Property-Based Testing in Python: Hypothesis Finds the Bugs Your Examples Miss

Property-based testing explained with Hypothesis tests we ran: properties vs examples, strategies, shrinking, the real bugs it found in our…

Read article →
Databases & SQL

SQL Pagination Explained: OFFSET vs Keyset, With a Million-Row Test

SQL pagination explained with a million-row test we ran: LIMIT and OFFSET, why deep pages get slow, keyset (cursor) pagination,…

Read article →
Databases & SQL

SQL EXISTS vs IN: Differences, the NOT IN NULL Trap and Performance

SQL EXISTS vs IN explained with queries we ran: how each works, why NOT IN returns no rows when a…

Read article →
Software Development

Python Logging Explained: Levels, Handlers, Formatters and Mistakes to Avoid

Python logging explained with code we ran: levels, basicConfig quirks, named loggers, handlers and formatters, logger.exception, lazy formatting, duplicate logs…

Read article →
Software Development

JavaScript Map vs Object: Key Differences, Pitfalls and a Benchmark

JavaScript Map vs Object explained with code we ran in Node.js: key types, ordering, the prototype trap, JSON, size, WeakMap…

Read article →
Software Development

Python Type Hints Explained: Annotations, mypy and the Errors It Catches

Python type hints explained with a real mypy run: basic annotations, Optional and unions, TypedDict, Literal, Protocol, generics, Callable, strict…

Read article →
Artificial Intelligence

LLM Tokens Explained: How AI Models Read Text, Count Costs and Fill Context Windows

LLM tokens explained with a tokenizer we ran: how text is split, why counts differ by language and tokenizer, context…

Read article →
DevOps

Semantic Versioning Explained: MAJOR.MINOR.PATCH, Ranges and Release Rules

Semantic versioning explained with code we ran: MAJOR.MINOR.PATCH rules, pre-releases, correct version sorting, caret and tilde ranges, 0.x versions, lockfiles…

Read article →
DevOps

Git Reset vs Revert: How to Undo Commits Safely, With a Tested Example

Git reset vs revert explained with a repository we built: soft, mixed and hard reset, revert commits, reverting merges, recovering…

Read article →
Software Testing

The Test Pyramid Explained: Layers, Ratios and When to Break the Shape

The test pyramid explained: unit, integration and end-to-end layers, sensible ratios, the ice cream cone anti-pattern, the testing trophy and…

Read article →
Test Automation

pytest Fixtures Explained: Scope, yield Teardown, conftest.py and Factories

pytest fixtures explained with a suite we ran: how fixtures work, scopes, yield teardown, conftest.py, factory fixtures, parametrized fixtures, built-ins…

Read article →
Databases & SQL

SQL Upsert Explained: INSERT ON CONFLICT, MERGE and the REPLACE Trap

SQL upsert explained with queries we ran: INSERT ON CONFLICT DO UPDATE and DO NOTHING, the excluded row, conditional updates,…

Read article →
Databases & SQL

SQL LIKE Operator Explained: Wildcards, Case Sensitivity and Performance

The SQL LIKE operator explained with queries we ran: % and _ wildcards, escaping, NOT LIKE and NULL, case sensitivity…

Read article →
Artificial Intelligence

AI Hallucinations Explained: Why Language Models Make Things Up and How to Reduce It

AI hallucinations explained: what they are, why language models produce them, common types, how to reduce them with grounding and…

Read article →
Test Automation

Mocking in Python: unittest.mock, patch and the Mistakes That Make Tests Lie

Mocking in Python with unittest.mock, tested: Mock and return_value, side_effect, patching where a name is used, spec and autospec, mocking…

Read article →
Software Testing

Code Coverage Explained: Line vs Branch Coverage and What 100% Really Means

Code coverage explained with a real coverage.py run: line, branch and condition coverage, reading a report, why 100% coverage can…

Read article →
Artificial Intelligence

What Are AI Agents? How They Work, With a Simple Agent Loop You Can Run

What are AI agents? A plain guide to the agent loop, tools, memory and guardrails, with a small Python loop…

Read article →
Test Automation

TDD vs BDD: Key Differences, One Feature Built Both Ways and When to Use Each

TDD vs BDD explained with one discount feature built both ways: red-green-refactor with code we ran, Given-When-Then scenarios, tools, trade-offs…

Read article →
Software Testing

User Acceptance Testing (UAT): Process, Checklist and Real Examples

User acceptance testing explained: who runs it, how it differs from QA, a seven-step process, a UAT test case template,…

Read article →
Artificial Intelligence

What Are Embeddings? Vectors and Cosine Similarity Explained Simply

What are embeddings? A plain-language guide to vectors, cosine similarity and semantic search, with a small example we ran, common…

Read article →
Test Automation

Flaky Tests: What Causes Them and How to Fix Them for Good

Flaky tests explained with demos we ran: the main causes, how to confirm and diagnose one, proper fixes for timing,…

Read article →
Software Testing

Load Testing vs Stress Testing: Differences, Metrics and k6 Examples

Load testing vs stress testing explained: what each proves, spike and soak tests, the metrics that matter, why averages mislead,…

Read article →