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}`));
Output
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!)
Output
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
Output
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!"
Output
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:

🎯 Higher-Order Functions Interview Deck
Question 1 of 5
⭐ Easy • HOF Definition HOF Fundamentals
function operate(fn, val) {
    return fn(val);
}
Why is operate considered a Higher-Order Function?
A) It accepts a function ('fn') as an argument
B) It uses the return statement
C) It operates on numbers
D) It is an asynchronous function
⚡ Medium • Multi-step Currying Currying Evaluation
const calc = a => b => c => (a * b) + c;

console.log(calc(2)(3)(4));
What will be logged to the console?
A) 10
B) 24
C) 9
D) undefined
⚡ Medium • Infinite Currying Infinite Currying
function add(a) {
    return function(b) {
        if (b !== undefined) return add(a + b);
        return a;
    };
}

console.log(add(1)(2)(3)(4)());
What is the output of add(1)(2)(3)(4)()?
A) [Function]
B) 10
C) undefined
D) NaN
⭐ Easy • Pipe Pipeline Flow Pipelines
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);

const double = n => n * 2;
const add2 = n => n + 2;

const transform = pipe(double, add2, double);
console.log(transform(3));
What will be logged to the console?
A) 16
B) 12
C) 10
D) 20
⭐ Easy • Built-in HOFs Array HOFs
const names = ["anshuman", "priya"];
const formatted = names.map(str => str.toUpperCase());

console.log(formatted);
What is the value of formatted?
A) ['ANSHUMAN', 'PRIYA']
B) 'ANSHUMAN PRIYA'
C) ['anshuman', 'priya']
D) undefined

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.

Your output will appear here.