Learn the vocabulary of a function that accepts or returns another function instead of only plain data.
0 / 5 completed
1 / 5
At standup, a dev mentions a function that either accepts another function as an argument or returns a function as its own result, rather than only ever accepting and returning plain data values. What is this called?
A higher-order function either accepts another function as an argument, like passing a comparison function into a sort routine, or returns a function as its own result, like a function that builds and returns a specialized validator, rather than being limited to only plain data values as its inputs and outputs. A closure is a related but distinct concept about a function retaining access to variables from an enclosing scope. This ability to treat functions themselves as values that can be passed around and returned is exactly what unlocks patterns like `map`, `filter`, and `reduce`, all of which are higher-order functions.
2 / 5
During a design review, the team replaces several near-identical loops, each only differing in the one operation applied to every element, with a single `map` call parameterized by whichever operation function is passed in. Which capability does this higher-order approach provide?
This higher-order approach provides reusing one generic traversal implementation across many different operations, since the actual looping logic, walking every element in sequence, lives in exactly one place, `map` itself, and only the specific operation applied to each element changes based on whichever function is passed in as an argument. Writing a separate loop for every different operation instead duplicates that same traversal logic over and over, with only the small inner operation actually differing between them. This separation between the fixed traversal and the pluggable operation is exactly why `map`, `filter`, and similar higher-order functions cut down so much repetitive looping code.
3 / 5
In a code review, a dev notices a function accepts a callback as its parameter but never actually invokes it anywhere in its own body, despite the parameter being named and typed as if it were meant to be called. What does this represent?
This is a higher-order function whose accepted callback is silently unused, meaning the function technically satisfies the shape of a higher-order function by accepting another function as a parameter, but never actually invokes that callback anywhere in its own body, so whatever behavior the caller expected from passing it in simply never happens. A cache eviction policy is an unrelated concept about discarded cache entries. This is exactly the kind of quiet, easy-to-miss bug a reviewer needs to catch, since the function's signature alone gives no indication that the passed-in callback is being silently ignored.
4 / 5
An incident report shows a notification feature silently failed to send any alerts, because a higher-order function was refactored to accept an `onComplete` callback parameter, but the refactor never actually added a call to that callback anywhere in the function's body. What practice would prevent this?
Reviewing the refactored function's body specifically to confirm every accepted callback parameter is actually invoked at the appropriate point catches exactly this kind of silent gap, where a parameter's presence in the signature falsely implies it's actually being used, which is exactly the fix for the missing-alerts incident described here. Continuing to accept the `onComplete` parameter without ever calling it anywhere in the body is exactly what caused the notification feature to silently do nothing. This kind of check is exactly why a careful reviewer traces every parameter, especially a callback, from its declaration in the signature to an actual call site in the body, rather than assuming a well-named parameter is automatically being used correctly.
5 / 5
During a PR review, a teammate asks why the team prefers passing a comparison function into a generic sort routine as a higher-order function instead of writing a separate, hand-tuned sort implementation for every different type of data that needs sorting. What is the reasoning?
A single generic sort implementation, parameterized by whatever comparison function gets passed in as an argument, reuses the exact same underlying sorting logic, like the same partitioning or merging steps, across every different data type that needs sorting, with only the comparison rule itself changing per call. Writing a separate, hand-tuned sort implementation for every different data type instead duplicates that same core sorting logic over and over, multiplying the amount of code that has to be maintained, tested, and kept free of bugs as more data types are added. The tradeoff is that the generic higher-order sort routine has to be written carefully enough to work correctly for any comparison function it might be handed, rather than being specialized and potentially optimized for one particular data type's specific characteristics.