Higher-Order Functions
Learn how to supercharge your code by treating functions like values, currying inputs, and building data transformation pipelines.
1. What is a Higher-Order Function (HOF)?
In JavaScript, functions are First-Class Citizens — you can treat them just like numbers or strings! A Higher-Order Function is simply a function that does at least one of these two things:
- 1. Takes another function as an input (like
.map()or.filter()) - 2. Returns a brand new function as its output (like function factories and currying)
💡 Think of a Power Tool with Interchangeable Attachments
The power drill is the Higher-Order Function. The drill bits (screwdriver bit, sanding bit, drill bit) are the callback functions you plug into it. You change what the tool does simply by swapping the attachment!
// 1. Higher-Order Function taking a function as an input:
function repeatTask(times, action) {
for (let i = 1; i <= times; i++) {
action(i); // Run the passed function
}
}
repeatTask(3, (num) => console.log(`Running step #${num}`));
Running step #1 Running step #2 Running step #3
2. Function Factories & Currying
Currying is the technique of converting a function that takes multiple arguments into a chain of functions that take one argument at a time:
// 1. Regular Function: takes 2 arguments at once
function multiply(a, b) {
return a * b;
}
// 2. Curried Function: returns a function waiting for the second input
const createMultiplier = factor => number => number * factor;
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(10)); // 20
console.log(triple(10)); // 30
console.log(createMultiplier(5)(4)); // 20 (Direct chaining!)
20 30 20
3. The Famous Infinite Currying Interview Question
In tech interviews, companies often ask: "Can you write a function add(1)(2)(3)...() that can take any number of calls and returns the total when called with no arguments?"
function addInfinite(a) {
return function(b) {
// If an argument is provided, keep chaining:
if (b !== undefined) {
return addInfinite(a + b);
}
// If called empty (), return the accumulated total:
return a;
};
}
console.log(addInfinite(1)(2)(3)()); // 6
console.log(addInfinite(5)(10)(20)(50)()); // 85
6 85
4. Functional Pipelines: `pipe()`
Instead of nesting multiple function calls like exclaim(capitalize(trim(text))), you can build a clean pipeline that flows data from left to right:
const pipe = (...functions) => (initialValue) =>
functions.reduce((currentValue, currentFunction) => currentFunction(currentValue), initialValue);
const trimText = str => str.trim();
const uppercase = str => str.toUpperCase();
const addExclamation = str => `${str}!`;
// Build a clean pipeline:
const cleanHeading = pipe(trimText, uppercase, addExclamation);
console.log(cleanHeading(" learn javascript ")); // "LEARN JAVASCRIPT!"
LEARN JAVASCRIPT!
5. Quick HOF Summary
| Concept | What it Means | Real-World Example |
|---|---|---|
| Higher-Order Function | Function accepting or returning another function | arr.map(fn), withLogging(fn) |
| Currying | Splitting f(a, b) into f(a)(b) |
applyDiscount(10)(price) |
| Pipeline (pipe) | Running data through a list of functions sequentially | pipe(trim, sanitize, save) |
6. Higher-Order Functions Interview Deck
Test your knowledge on function currying, infinite currying termination, functional pipelines, and HOF identification:
7. Practice Challenge
🎯 Coding Challenge: Custom Functional Pipeline
1. Build a generic pipe(...fns) higher-order utility function using reduce.
2. Create a pipeline of three functions: multiplyBy2, add10, and formatCurrency.
3. Pass the initial number 25 through the pipeline and print the result.