Higher-Order Functions and Recursion in JavaScript
Higher-Order Functions and Recursion in JavaScript
~13 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026
Two advanced, closely related function concepts: functions that take other functions as parameters or return them ("higher-order functions", which we already use daily via map/filter/reduce from chapter 11), and functions that call THEMSELVES (recursion).
What is a higher-order function?
A function is "higher-order" if it has at least ONE of two properties: it takes a function as an argument, OR it returns a function.
// Takes a function as an argument:
function processTransactions(transactions, processFn) {
return transactions.map(processFn);
}
const amounts = processTransactions(
[{ amount: 2400 }, { amount: -850 }],
t => t.amount
);
console.log(amounts); // [2400, -850]Functions that return functions
A powerful pattern: a function FACTORY that creates a specialized function based on a parameter – for our budget app, e.g. a factory for category filters:
function createCategoryFilter(category) {
return function (transaction) {
return transaction.category === category;
};
}
const transactions = [
{ description: 'Rent', category: 'Housing', amount: -850 },
{ description: 'Electricity', category: 'Housing', amount: -60 },
{ description: 'Movies', category: 'Leisure', amount: -18 },
];
const isHousing = createCategoryFilter('Housing'); // EXACTLY like chapter 16: a closure!
const housingCosts = transactions.filter(isHousing);
console.log(housingCosts); // Rent and ElectricityTipp: This is the same closure mechanism from chapter 16 – higher-order functions and closures often go hand in hand in practice: the returned function "remembers" the outer function's category parameter.
Function composition: combining small functions
const onlyExpenses = transactions => transactions.filter(t => t.amount < 0);
const sumAmounts = transactions => transactions.reduce((s, t) => s + t.amount, 0);
function calculateTotalExpenses(transactions) {
return sumAmounts(onlyExpenses(transactions));
}
console.log(calculateTotalExpenses(transactions)); // -928Recursion: a function calling itself
A recursive function always needs two parts: a base case ("when does the recursion stop?"), and a recursive case that shrinks the problem and calls itself again:
function factorial(n) {
if (n <= 1) {
return 1; // base case
}
return n * factorial(n - 1); // recursive case - a smaller problem
}
console.log(factorial(5)); // 120 (5 * 4 * 3 * 2 * 1)Achtung: If the base case is missing or never reached, it causes infinite recursion and a "Maximum call stack size exceeded" error once the call stack (chapter 23) fills up.
Practical example: nested category tree totals
Recursion is especially suited to tree structures – e.g. if categories are allowed to have subcategories:
const categoryTree = {
name: 'All expenses',
amount: 0,
subcategories: [
{ name: 'Housing', amount: -910, subcategories: [] },
{
name: 'Leisure', amount: 0,
subcategories: [
{ name: 'Movies', amount: -18, subcategories: [] },
{ name: 'Sports', amount: -35, subcategories: [] },
],
},
],
};
function sumTree(node) {
let total = node.amount;
for (const subcategory of node.subcategories) {
total += sumTree(subcategory); // recursive call per level
}
return total;
}
console.log(sumTree(categoryTree)); // -963