Higher-Order Functions
A higher-order function is a function that works with other functions.
It can:
- accept a function as an argument
- return a function
- do both
JavaScript uses higher-order functions everywhere.
Function as an Argument
function repeat(times, action) {
for (let index = 0; index < times; index++) {
action(index);
}
}
repeat(3, (index) => {
console.log(`Run ${index}`);
});repeat is a higher-order function because it accepts action.
Returning a Function
function createMultiplier(multiplier) {
return function multiply(value) {
return value * multiplier;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15createMultiplier returns a new function.
This works because of closures.
The returned function remembers multiplier.
Array Methods Are Higher-Order Functions
Many array methods accept callback functions.
const numbers = [1, 2, 3, 4];
const doubled = numbers.map((number) => number * 2);
const even = numbers.filter((number) => number % 2 === 0);
const total = numbers.reduce((sum, number) => sum + number, 0);map, filter, and reduce are higher-order functions.
They let you describe what should happen to each value.
map()
Use map() to transform every item.
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
];
const names = users.map((user) => user.name);
console.log(names); // ["Alice", "Bob"]map() returns a new array with the same length.
filter()
Use filter() to keep some items.
const products = [
{ name: "Keyboard", inStock: true },
{ name: "Monitor", inStock: false },
{ name: "Mouse", inStock: true },
];
const availableProducts = products.filter((product) => product.inStock);
console.log(availableProducts);filter() returns a new array.
The result may be shorter than the original.
reduce()
Use reduce() to combine many values into one value.
const numbers = [10, 20, 30];
const total = numbers.reduce((sum, number) => {
return sum + number;
}, 0);
console.log(total); // 60The second argument, 0, is the initial value.
forEach() vs map()
forEach() is for side effects.
users.forEach((user) => {
console.log(user.name);
});map() is for transformations.
const names = users.map((user) => user.name);Do not use map() only to run side effects.
users.map((user) => console.log(user.name)); // avoidUse forEach() for that.
Custom Higher-Order Function
function withLogging(fn) {
return function loggedFunction(...args) {
console.log("Calling function with:", args);
return fn(...args);
};
}
function add(a, b) {
return a + b;
}
const loggedAdd = withLogging(add);
console.log(loggedAdd(2, 3)); // 5withLogging takes a function and returns a new function with extra behavior.
This pattern is common in middleware, decorators, event handling, and utility libraries.
Best Practices
Use map() when you want a transformed array.
Use filter() when you want a subset.
Use reduce() when you want to combine values.
Use forEach() for side effects.
Name callback functions when the logic gets complex.
Keep callbacks small and readable.
Common Mistakes
Mistake 1: Forgetting to Return From map()
const doubled = numbers.map((number) => {
number * 2;
});
console.log(doubled); // [undefined, undefined, undefined]Correct:
const doubled = numbers.map((number) => {
return number * 2;
});Or:
const doubled = numbers.map((number) => number * 2);Mistake 2: Using map() for Side Effects
users.map((user) => console.log(user.name));Use forEach() when you do not need the returned array.
Mistake 3: Missing reduce Initial Value
const total = numbers.reduce((sum, number) => sum + number);This can work, but an explicit initial value is clearer and safer.
const total = numbers.reduce((sum, number) => sum + number, 0);Summary
Higher-order functions work with other functions.
- They can accept functions as arguments.
- They can return functions.
map,filter,reduce, andforEachare higher-order functions.- Use the right array method for the job.
- Returned functions can remember values through closures.