In JavaScript, what makes a function a higher-order function, and which property of the language makes higher-order functions possible?
answer
- functions are values, not syntax
- two shapes: takes one, returns one
- callback is a role, not a type
- name versus name-with-parentheses
basics
~20 sA higher-order function takes a function as an argument, returns a function, or both. It works because JavaScript functions are first-class values: they can be stored in variables, put in arrays or objects, passed as arguments, and returned like any other value.
solid answer
~40 sA function is higher-order if it operates on functions — it accepts one or more functions as arguments, returns a function, or does both. Nothing special enables this: in JavaScript a function *is* a value, a callable object, so `const f = function () {}` stores it, `arr.push(f)` puts it in an array, and `run(f)` hands it to someone else exactly like a number or a string. Array methods such as `map`, `filter` and `sort` are higher-order because they take a callback; a factory like `makeAdder(5)` is higher-order because it returns a function. The single mistake to avoid is writing `run(f())` when you meant `run(f)` — the parentheses call the function and pass its *result* instead of the function itself.
code
javascript · 14 lines// Shape 1: takes a function
function applyTwice(fn, value) {
return fn(fn(value));
}
// Shape 2: returns a function
function makeAdder(step) {
return (n) => n + step;
}
const addTen = makeAdder(10);
console.log(applyTwice(addTen, 5)); // 25
console.log(typeof addTen); // "function"
console.log(addTen.name); // "" (anonymous arrow returned from makeAdder)go deeper
Be ready to state the definition and write both shapes on a whiteboard: one function that takes another, one that returns another. Say plainly that functions are values in JavaScript.
Explain the argument contract the higher-order function imposes — how many arguments the callback receives and what its return value is used for — and show the passing-versus-calling bug and how you spot it in review.
Show judgment about when the abstraction pays for itself. An interviewer expects you to point out that a callback inverts control: the caller supplies behaviour but the callee owns timing, error handling, and how many times the callback runs.
Own the API-design angle: whether an extension point should be a function, a configuration object, or data, and what handing users a callback commits your library to — invocation timing, argument stability, and error propagation you can no longer change without a breaking release.
## Functions are values In JavaScript a function is an ordinary value — specifically, an object that happens to be callable. Anything you can do with a number you can do with a function: bind it to a variable, store it in an array, use it as an object property, pass it to another function, or return it from one. This is what "first-class functions" means, and it is the entire foundation of the higher-order style. ```js const double = (n) => n * 2; const ops = [double, (n) => n + 1]; // stored in an array const registry = { double }; // stored as a property console.log(typeof double); // "function" ``` Note that `typeof` reports `"function"`, but a function is still an object underneath: it has properties (`double.name` is `"double"`), and you can attach your own. ## The two shapes A higher-order function is any function that **takes a function as an argument**, **returns a function**, or both. Taking a function — the callback shape: ```js function applyTwice(fn, value) { return fn(fn(value)); } applyTwice((n) => n + 3, 1); // 7 ``` `applyTwice` knows nothing about what `fn` does. The caller supplies the behaviour; `applyTwice` supplies the control flow. That inversion is the whole point. Returning a function — the factory shape: ```js function makeAdder(step) { return (n) => n + step; } const addTen = makeAdder(10); addTen(5); // 15 ``` `makeAdder` is called once and produces a specialised function you can call many times. Standard-library examples of the first shape are everywhere: `Array.prototype.map`, `Array.prototype.filter`, `Array.prototype.sort` and `Array.prototype.forEach` all accept a callback; `Object.defineProperty` accepts getter and setter functions. ## Callback is a role, not a type The word *callback* describes a function's role rather than anything about the function itself: it is simply a function that somebody else will call, at a time of their choosing. Any function can be one. The receiving code decides how many arguments to pass it, when to call it, and what to do with its return value — that contract is defined entirely by the higher-order function, and it is why reading the documentation of the callback signature matters. ## Passing versus calling The most common beginner bug is a stray pair of parentheses: ```js function schedule(task) { /* stores task, runs it later */ } schedule(cleanup); // passes the function — usually what you want schedule(cleanup()); // CALLS cleanup now and passes its return value ``` Both lines are valid JavaScript, so nothing throws. The second one runs `cleanup` immediately and then hands `schedule` whatever it returned — very often `undefined`, which then fails much later with a confusing "task is not a function" message. Whenever you write a function name into an argument list, check whether you meant the name or the call. ## Why the pattern is worth learning Higher-order functions let you factor out *what varies*. Instead of writing one loop per operation, you write one traversal that accepts the operation. Instead of ten near-identical validators, you write one validator factory parameterised by a rule. Event-driven and asynchronous APIs are unavoidably higher-order — you cannot hand the runtime code to run later except by handing it a function. Composition helpers, wrappers such as `once` or `memoize`, and middleware chains are all just functions that take and return functions. A small warning about vocabulary: not every function-taking function is worth abstracting. Interviewers ask you to write a higher-order function from scratch mainly to check that you really see a function as a value, not as a piece of syntax that must be immediately invoked. Demonstrating that by writing a four-line factory is worth more than reciting a definition.
- Is every function that accepts a callback worth calling higher-order, or is the term reserved for library code?The term is purely structural — any function whose parameter or return value is a function qualifies, whether it is a three-line helper in your own file or `Array.prototype.map`. There is no threshold of sophistication. What varies is usefulness: the abstraction earns its keep when it removes real duplication, not merely because it accepts a function.
- What actually happens if I write `schedule(cleanup())` instead of `schedule(cleanup)`?`cleanup` runs immediately, at the moment the argument list is evaluated, and its return value is passed to `schedule`. If `cleanup` returns nothing, `schedule` receives `undefined`, stores it, and blows up later with something like "task is not a function" — far from the real mistake. Nothing throws at the call site, which is what makes it a slow bug.
- How can a function be both an object and callable at the same time?Because a JavaScript function is an object with an internal call behaviour. `typeof` reports `"function"` to flag that it is callable, but it still has properties: `name`, `length`, and any property you attach yourself. That is why you can write `handler.cancelled = true` on a function you passed somewhere, and why functions can live in arrays and Maps like any other object.
A recipe card is not the meal. Passing the card lets someone cook whenever they like; cooking it yourself and handing over the plate is a different act — that is the difference between passing fn and passing fn().
saying these in an interview costs you the question
- Claims JavaScript needs special syntax to pass a function
- Writes fn() in an argument list when passing fn was meant
- Thinks only built-in array methods can be higher-order
- Says a callback must be anonymous or an arrow function
- Confuses returning a function with returning its call result