JavaScript Higher-Order Functions
A higher-order function is a function that either takes another function as an input, returns a function as its output, or does both. JavaScript treats functions as first-class citizens — you can store them in variables, pass them around, and return them just like numbers or strings.
Why the Name "Higher-Order"?
In mathematics, a function that operates on other functions is called higher-order. The concept carries into programming. A regular function works with data. A higher-order function works with other functions as if they were data.
Diagram: Regular vs Higher-Order Function
Regular Function: Input: numbers, strings, objects Output: numbers, strings, objects Higher-Order Function: Input: numbers, strings, functions ◄── functions as input Output: numbers, strings, functions ◄── functions as output
Type 1: Functions That Accept a Function
The most common pattern. You pass a function as an argument, and the outer function uses it.
function runTwice(action) {
action();
action();
}
runTwice(function() {
console.log("Hello!");
});
// Output:
// Hello!
// Hello!
runTwice is the higher-order function. It takes action (a function) and calls it twice.
Type 2: Functions That Return a Function
A higher-order function can create and return a new function. This is powerful because you can build customized functions on the fly.
function makeMultiplier(factor) {
return function(number) {
return number * factor;
};
}
let double = makeMultiplier(2);
let triple = makeMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
Diagram: makeMultiplier Factory
makeMultiplier(2) ──► returns a function that multiplies by 2
│
▼
double = fn(n) => n * 2
makeMultiplier(3) ──► returns a function that multiplies by 3
│
▼
triple = fn(n) => n * 3
double(5) → 10
triple(5) → 15
Built-In Higher-Order Functions
JavaScript arrays come with several built-in higher-order functions. These are the most important ones to know.
map — Transform Every Item
map runs a function on each item and returns a new array with the results.
let temperatures = [0, 20, 37, 100]; // Celsius
let fahrenheit = temperatures.map(function(c) {
return (c * 9/5) + 32;
});
console.log(fahrenheit); // [32, 68, 98.6, 212]
Diagram: map Flow
Input: [0, 20, 37, 100]
│ │ │ │
fn → fn → fn → fn → fn (apply conversion to each)
│ │ │ │
Output: [32, 68, 98.6, 212]
filter — Keep Only What Passes
filter keeps items where the function returns true, and drops the rest.
let scores = [45, 72, 38, 90, 55, 80];
let passed = scores.filter(function(score) {
return score >= 60;
});
console.log(passed); // [72, 90, 80]
reduce — Collapse Into One Value
reduce runs a function on each item and carries a running total (accumulator) through the array.
let cart = [200, 450, 150, 300];
let total = cart.reduce(function(accumulator, item) {
return accumulator + item;
}, 0);
console.log(total); // 1100
Diagram: reduce Step by Step
Start: acc = 0 Step 1: acc = 0 + 200 = 200 Step 2: acc = 200 + 450 = 650 Step 3: acc = 650 + 150 = 800 Step 4: acc = 800 + 300 = 1100 Result: 1100
find — Get the First Match
let users = [
{ name: "Anjali", age: 22 },
{ name: "Rohan", age: 30 },
{ name: "Meera", age: 17 }
];
let adult = users.find(function(user) {
return user.age >= 18;
});
console.log(adult.name); // "Anjali"
every and some
let ages = [22, 30, 25, 19];
console.log(ages.every(a => a >= 18)); // true — all adults
console.log(ages.some(a => a >= 30)); // true — at least one is 30+
Chaining Higher-Order Functions
You can chain these methods together to build a pipeline of transformations.
let products = [
{ name: "Shirt", price: 500, inStock: true },
{ name: "Shoes", price: 2000, inStock: false },
{ name: "Cap", price: 300, inStock: true },
{ name: "Jacket", price: 3000, inStock: true }
];
let result = products
.filter(p => p.inStock) // only available items
.map(p => p.price) // extract prices
.reduce((sum, p) => sum + p, 0); // total
console.log(result); // 3800 (500 + 300 + 3000)
Diagram: Chained Pipeline
products (4 items)
│
▼ filter (inStock only)
[Shirt, Cap, Jacket] (3 items)
│
▼ map (prices only)
[500, 300, 3000]
│
▼ reduce (sum)
3800
Creating Your Own Higher-Order Function
function applyToAll(arr, transform) {
let result = [];
for (let item of arr) {
result.push(transform(item));
}
return result;
}
let numbers = [1, 2, 3, 4];
let squared = applyToAll(numbers, n => n * n);
let doubled = applyToAll(numbers, n => n * 2);
console.log(squared); // [1, 4, 9, 16]
console.log(doubled); // [2, 4, 6, 8]
The same applyToAll function does different things depending on what transform function you give it.
Benefits of Higher-Order Functions
| Benefit | What It Means |
|---|---|
| Reusability | Write one function, use with many behaviors |
| Readability | Code describes what it does, not how step by step |
| Composability | Chain small functions to build complex logic |
| Less code | No need to write the same loop structure repeatedly |
Summary
Higher-order functions treat other functions as values. They accept functions as arguments, return functions, or both. JavaScript's built-in array methods — map, filter, reduce, find, every, and some — are all higher-order functions. They make code shorter, cleaner, and easier to chain together into data pipelines.
