
Higher-Order Functions in JavaScript
Higher-order functions are one of the most important ideas in JavaScript, and you're probably already using them without realizing it. This blog explains what makes a function "higher-order," why they matter, and how methods like map, filter, and setTimeout all rely on this same simple idea.
If you've ever used .map(), .filter(), setTimeout(), or addEventListener(), you've already used a higher-order function. You just didn't know it had a name.
That's actually good news. It means this concept isn't some advanced, hard-to-reach idea. It's something you already use every day. This blog just gives it a name, explains why it works, and shows you how to write your own.

What is a higher-order function?
A higher-order function is simply a function that does at least one of these two things:
It takes another function as one of its inputs, or
It returns a function as its result
That's the whole definition. Nothing more complicated than that. Any function that does either of these things is called "higher-order," and any function that does neither is called a regular, or "first-order," function.
This is only possible in JavaScript because of one core idea: functions are values. In JavaScript, a function isn't some special, separate thing. It can be stored in a variable, passed around, and used just like a number or a string can be.
js
const greet = function () {
console.log("Hello!");
};
console.log(typeof greet); // "function"Because functions are just values, you can pass them into other functions, the same way you'd pass in a number or a string. That one idea is the entire foundation of higher-order functions.
A function that takes another function
Here's a simple example. We'll write a function called repeat that runs another function a certain number of times.
js
function repeat(times, action) {
for (let i = 0; i < times; i++) {
action(i);
}
}
repeat(3, function (i) {
console.log("Running number " + i);
});
// Output:
// Running number 0
// Running number 1
// Running number 2repeat is a higher-order function because it takes action as an input, and action is itself a function. Every time the loop runs, repeat calls action, passing in the current number. The function we pass in decides what actually happens on each run. repeat doesn't care what action does, it just knows when to call it.
This is a powerful idea. repeat can be reused for anything, not just logging numbers.
js
repeat(3, function (i) {
console.log("Item " + i + " added to cart");
});Same repeat function, completely different behavior, just by passing in a different function.
A function that returns another function
Now let's look at the second kind of higher-order function, one that returns a function instead of taking one in.
js
function multiplyBy(factor) {
return function (number) {
return number * factor;
};
}
const double = multiplyBy(2);
const triple = multiplyBy(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15multiplyBy is higher-order because it returns a brand new function every time you call it. double and triple are both functions created by multiplyBy, each one remembering a different value for factor. This works because of closures, something we covered in detail in our
double and triple remember their own separate factor values.The built-in higher-order functions you already use
JavaScript comes with several higher-order functions built right in, and you've almost certainly used them already.
map, filter, and reduce all take a function as an input, and use it to decide what to do with each item in an array. We covered these in detail in our
js
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(function (num) {
return num * 2;
});setTimeout takes a function and runs it later, after a certain amount of time.
js
setTimeout(function () {
console.log("This runs after 2 seconds");
}, 2000);addEventListener takes a function and runs it whenever a specific event happens, like a click or a key press.
js
button.addEventListener("click", function () {
console.log("Button was clicked");
});In every one of these examples, you're handing a function to another function, and trusting it to call your function at the right time. That's the higher-order function pattern, showing up everywhere in JavaScript, whether you noticed it or not.
[IMAGE: A dark background diagram showing four labeled boxes in a row - map, filter, setTimeout, addEventListener - each with a small arrow pointing into it labeled "your function goes in here", showing the same shared pattern across all four]
Why do higher-order functions actually matter?
The real benefit is reusability. Without higher-order functions, you'd have to write a new, slightly different loop or a new block of logic every single time you needed to do something similar. With higher-order functions, you write the repeating structure once, like repeat, or like map, and then just plug in different functions to change what actually happens each time.
This also makes code easier to read. Seeing numbers.filter(isEven) immediately tells you what's happening, filtering numbers using some rule called isEven, without needing to read a full loop to figure that out.
Writing your own higher-order function
Let's write one more practical example, a function that adds simple logging around any other function, without changing that function itself.
js
function withLogging(fn) {
return function (...args) {
console.log("Calling function with:", args);
const result = fn(...args);
console.log("Result:", result);
return result;
};
}
function add(a, b) {
return a + b;
}
const loggedAdd = withLogging(add);
loggedAdd(3, 4);
// Logs: Calling function with: [3, 4]
// Logs: Result: 7withLogging is higher-order in both ways at once. It takes a function (fn) as an input, and it also returns a brand new function. That returned function calls the original fn, but wraps some extra behavior around it, in this case, logging. Notice that add itself never had to change. We wrapped new behavior around it from the outside, which is one of the most useful things higher-order functions let you do.
Common mistakes beginners make
The most common mistake is calling the function instead of passing it. Writing repeat(3, action()) instead of repeat(3, action) runs action immediately and passes its result into repeat, instead of passing the function itself. Always pass the function by its name, without the parentheses, unless you're intentionally calling it right there.
The second common mistake is forgetting that a function returned by another function needs to actually be called to run. Writing const double = multiplyBy(2); and expecting double to already equal a number is a common early confusion. double is a function, not a number, so you still need to call double(5) to actually get a result.
Quick reference - what makes a function higher-order
Pattern | Example | What makes it higher-order |
|---|---|---|
Takes a function as input |
| The function passed in decides what happens |
Returns a function |
| Creates a new, customized function each time |
Built-in examples |
| All accept a function you provide |
Interview Questions
What is a higher-order function? A function that either takes another function as an argument, or returns a function as its result, or both. It's possible in JavaScript because functions are treated as values.
Give an example of a built-in higher-order function. map, filter, and reduce are all higher-order functions, since each one takes a function as an argument and uses it to decide what happens to each item in an array.
What's the difference between a higher-order function and a callback function? A callback is the function you pass in. A higher-order function is the function that accepts (or returns) that callback. map is a higher-order function, and the function you pass into .map() is the callback.
Why are higher-order functions useful? They let you reuse the same structure or loop while changing the actual behavior just by passing in a different function, which reduces repeated code and makes logic easier to read.
Can a function be higher-order without taking any arguments? Yes. If a function returns another function, like multiplyBy does, it's still higher-order, even if it doesn't take a function in as an argument.
Wrapping up
A higher-order function isn't a special or advanced feature you have to learn separately. It's just a natural result of functions being treated as values in JavaScript. Once you can spot the pattern, a function taking another function in, or handing one back out, you'll start noticing it everywhere, in the built-in methods you already use, and in your own code once you start writing it on purpose.
If you haven't already, our
Callback Functions in JavaScript post pairs well with this one, since callbacks are simply the functions you pass into a higher-order function. And if you want to see the closure mechanics behind functions that return other functions, our Closures in JavaScript post covers that in detail.Related Articles
More insights you might enjoy

Async/Await in JavaScript - How It Actually Works and Why It Exists
How async/await works in JavaScript - async functions, await, error handling, parallel vs sequential execution, and the most common mistakes explained.

JavaScript Closures - The Concept Interviewers Actually Test
Closures are one of the most asked-about JavaScript concepts in interviews, and also one of the most misunderstood. This blog explains what a closure actually is, why functions can remember variables from outside their own scope, and where closures show up in real code

React vs Next.js: What's Actually Different and When to Use Which
React and Next.js are often confused - one is a UI library, the other is a full framework built on top of it. This post breaks down the real differences: rendering strategies, routing, API routes, and when to pick one over the other.

How React's useEffect Actually Works - And Why Developers Misuse It
useEffect is one of the most used hooks in React and also one of the most misunderstood. This guide covers the dependency array, cleanup functions, the double render, and common mistakes that cause bugs.

Node.js and Express.js - What They Are, How They Differ, and How They Work Together
Node.js and Express.js are not the same thing. This guide explains what each does, how they work together, and covers routing, middleware, and error handling with real code.

How the JavaScript Event Loop Actually Works - A Deep Dive
A complete deep dive into the JavaScript event loop - the call stack, callback queue, microtask queue, and how they work together to make async JavaScript possible.

Comments
Sign in to join the conversation