Functions Are Values
In JavaScript, a function is a value like any other. You can store it in a variable, put it in an array, pass it to another function, or return it from one. That fact alone unlocks a whole style of programming:
Once you're comfortable treating functions as values, higher-order functions stop feeling mysterious. A higher-order function is just a function that either takes a function as an argument, returns a function, or both. That's the whole definition.
Taking a Function as an Argument
The most common form: a function that accepts a callback and runs it for you. You've already used these without thinking about it.
forEach is higher-order — it takes your function and calls it once per item. setTimeout is higher-order — it takes your function and calls it after a delay. You focus on what to do; they handle when and how many times.
Writing your own looks the same. Here's a tiny function that runs a callback only if a condition is true:
action is a parameter that happens to hold a function. Calling it with action() runs whatever was passed in.
The Three You'll Actually Use: map, filter, reduce
Arrays come with higher-order methods that replace most of the for loops you'd otherwise write. Learn these three and a huge amount of everyday code gets shorter and clearer.
map — transform every item
map calls your function once per item and collects the return values into a new array. Same length, transformed contents. The original array isn't modified.
filter — keep the ones that match
filter keeps items where the callback returns truthy and drops the rest. Return value is a new array, possibly shorter.
reduce — fold the array into one value
reduce is the general-purpose one. The callback receives the running accumulator and the current item; whatever you return becomes the next accumulator. The second argument (0 here) is the starting value.
You can chain them. This is where the style pays off:
Read it top to bottom: keep paid orders, pull out the price, sum them up. No loop, no mutable counter, no off-by-one to worry about.
Returning a Function From a Function
The other half of higher-order. A function that builds and returns another function:
multiplyBy(2) runs once and hands back a brand-new function. That new function still remembers factor — that's a closure, and it gets its own page later. For now, the takeaway: calling multiplyBy with different arguments gives you different specialised functions built from the same template.
This pattern shows up everywhere:
One definition, two reusable functions. Beats writing warn and info by hand and keeping them in sync.
Named Functions vs Inline Callbacks
You can pass an inline arrow function, or pass a function by name. Both work — pick whichever reads better:
When you pass isEven (no parentheses), you're handing over the function itself. Adding () would call it immediately and pass the result — a common beginner mistake:
nums.filter(isEven); // correct: passes the function
nums.filter(isEven()); // wrong: calls isEven with no args, passes the result
If the callback starts to sprawl past a couple of lines, pull it out and give it a name. The surrounding code usually reads better for it.
A Worked Example
Higher-order functions shine when you compose small pieces. Suppose you've got a list of products and want the names of affordable, in-stock items, uppercased:
Each helper has one job. Each array method does one transformation. The pipeline reads like a specification of what you want, not a description of how to loop.
When Not to Reach for Them
Higher-order methods are great — but they're not a loop replacement for every situation:
- If you need to stop partway through,
fororfor...ofwith abreakis clearer than trying to bail out offorEach. - If you're doing something async inside the callback,
mapandforEachwon't await it. Usefor...ofwithawait, orPromise.allwithmap. - If the callback is mutating shared state, you're drifting away from the style's strengths. Reach for a plain loop or refactor to return new values.
Used where they fit, map, filter, and reduce cut most of the loop boilerplate out of everyday code. Used everywhere, they start to hurt readability. Pick the tool that makes intent clearest.
Next: Objects
Functions aren't the only values worth building on. Objects are JavaScript's workhorse for grouping related data and behavior together — and they're what most of the arrays you just filtered and mapped were full of. That's the next page.
Frequently Asked Questions
What is a higher-order function in JavaScript?
A higher-order function is a function that does at least one of two things: takes another function as an argument, or returns a function as its result. Array.prototype.map, setTimeout, and addEventListener are all higher-order — they accept a callback and run it for you.
What's the difference between map, filter, and reduce?
map transforms each item and returns a new array of the same length. filter keeps items where the callback returns truthy and returns a (possibly shorter) array. reduce folds the array into a single value by combining items one at a time. All three are higher-order functions that take a callback.
Why would you return a function from another function?
To build small, configurable helpers without repeating logic. A function like multiplyBy(n) returns a new function that multiplies by n, so multiplyBy(2) and multiplyBy(10) give you two specialised functions from one definition. This pattern uses closures and is common in event handlers, middleware, and utility libraries.