AlgoInsight

Free lesson · JavaScript Basic to Advance

Interview Lens: Functions

Easy5 min read

The Question

Function-related interview questions cluster around five patterns:

"Explain the difference between function declarations and function expressions."

"What's the difference between an arrow function and a regular function?"

"Implement [array method] from scratch." Usually map, filter, reduce, or forEach.

"Write a debounce function." Or throttle. Or memoize. Or curry.

Some output-prediction puzzle involving callbacks, hoisting, or this.

These are core JavaScript questions. They come up in almost every JavaScript-focused interview, from new-grad screens to staff interviews. The good news: they're all preparable. The depth required scales with the seniority of the role, but the underlying material is the same.

Arun on the interview pattern and the practical strategy. Nikhil on the deeper technical material — especially the "implement this from scratch" challenges, where the interviewer is probing whether you actually understand the underlying mechanism or just the API.

Why They Ask It

Function questions are the cleanest test of JavaScript fluency. Almost everything else in the language — async, closures, prototypes, this — builds on functions. If you can't handle function questions cleanly, you can't handle anything that depends on them.

Three signals the interviewer is listening for:

Signal 1: Do you know modern syntax cold? Writing function(n) { return n * 2 } instead of n => n * 2 for a simple callback signals you haven't fully adopted post-ES6 JavaScript. Reaching for map, filter, reduce naturally signals modern fluency. The interviewer notices these choices without asking about them.

Signal 2: Can you reason about functions as values? "Implement your own map" tests whether you can think about a function as a thing that takes another function and applies it. Candidates who freeze on this question often don't have the "functions are values" mental model fully integrated.

Signal 3: Do you understand the gotchas? Hoisting differences between declarations and expressions. Arrow functions and this. Function identity in event listeners. These are knowledge tests — they probe whether you've studied the language deeply or just learned to use it.

I (Arun) failed an early interview on the "implement map" question. I tried to be clever about it — I started using reduce to build the result, which got me tangled up in arguments. The interviewer eventually said "just use a for loop, push to a result array, return it." That should have been my first instinct. Don't be clever in interviews. Be clear.

The Wrong Answers

Warning: The function mistakes interviewers see most often.

"A function declaration and a function expression are basically the same." They're not. Hoisting differs, reassignability differs, and modern style preferences differ. A candidate who waves the question away with "basically the same" signals they haven't thought about the distinction.

"Arrow functions are just shorter syntax for regular functions." Shorter syntax is one difference. The bigger difference is this binding — arrow functions inherit this from the surrounding scope, while regular functions get their own this based on how they're called. We cover this in Module 8, but knowing the difference exists is required for modern JavaScript interviews.

"I would use a for loop" for every iteration problem. When an interviewer asks you to transform an array, reaching for a manual for loop with push calls signals 2010-era JavaScript. The modern answer is map, filter, or reduce, picked based on what the transformation actually is.

Trying to implement methods using methods. "Implement map" doesn't mean "use map to implement map." Use a loop. Show that you understand what map does mechanically, not just how to call it.

The Right Answer

Three layers depending on which question is being asked.

The 30-Second Answer (for "what's the difference between X and Y" questions)

For declarations vs expressions:

"Function declarations are fully hoisted — you can call them before their declaration line. Function expressions are values assigned to variables, so they follow the hoisting rules of the variable keyword used. Modern style typically prefers function expressions assigned to const, often as arrow functions."

For arrow vs regular functions:

"Arrow functions have a more compact syntax — single-expression bodies don't need braces or return. The bigger semantic difference is this binding. Arrow functions inherit this from the surrounding scope; regular functions get their own this based on how they're called. Arrow functions also can't be used as constructors and don't have an arguments object."

Interactive animation: Kind first, then call site - an arrow inherits the surrounding this, a regular function gets its own.

The 2-Minute Answer (for conceptual questions)

Build on the 30-second answer:

"In practice, I use arrow functions for callbacks, array methods, and most assigned-to-const utility functions. The compact syntax keeps callback-heavy code readable. I use regular function syntax for object methods that need their own this and for constructors. I rarely use function declarations in new code, mainly because the consistency of const declarations matches the rest of modern JavaScript.

For the implementation questions — implement map, filter, reduce — the pattern is the same: take an array and a callback, iterate, apply the callback, return either a new array (for map, filter) or an accumulated value (for reduce). The trick is to show you understand the mechanism, not just the API. A clean implementation in five lines is worth more than a clever one in two."

The Deep Dive (Nikhil's territory)

For senior or staff interviews:

"Once you're confident with the basic function patterns, the deeper questions are about edge cases and implementation details.

For map, the spec actually iterates with a specific protocol — it uses the array's length at the start, skips holes in sparse arrays, and doesn't visit elements appended after iteration begins. Most candidate implementations ignore these details, which is fine for the interview but worth knowing for production code.

For reduce, the initial value matters. Calling [].reduce(fn) without an initial value throws. Calling [].reduce(fn, 0) returns 0. Senior interviews probe whether you've thought about empty-array edge cases.

For debounce and throttle — these come up constantly at senior levels — the difference is about when the wrapped function is allowed to run. Debounce delays execution until activity stops. Throttle caps execution rate to one call per period. Implementing each correctly requires understanding closures (Module 6) and setTimeout (Module 9). Many candidates get the high-level idea right but fumble the details of how the timer is reset.

For memoize, the implementation involves a cache (usually a Map) keyed by the arguments. The interesting questions are: how do you handle objects as cache keys? How do you handle multiple arguments? What's the memory growth pattern? These are conversation starters that distinguish "I know what memoize is" from "I've thought carefully about memoize.""

Implement Your Own map: The Walkthrough

When the interviewer asks for a from-scratch implementation, here's what they want to see.

function myMap(array, callback) {
  const result = [];
  for (let i = 0; i < array.length; i++) {
    result.push(callback(array[i], i, array));
  }
  return result;
}

console.log(myMap([1, 2, 3], n => n * 2));
console.log(myMap(["a", "b"], (s, i) => `${i}: ${s}`));

Walk through it out loud:

"Map takes an array and a callback. I'll iterate through the array. For each element, I'll call the callback with the element, the index, and the original array. The callback's return value goes into a result array. After the loop, I return the result. Important: I'm creating a new array, not modifying the original — that's how map works."

If the interviewer asks for filter next:

function myFilter(array, predicate) {
  const result = [];
  for (let i = 0; i < array.length; i++) {
    if (predicate(array[i], i, array)) {
      result.push(array[i]);
    }
  }
  return result;
}

console.log(myFilter([1, 2, 3, 4], n => n % 2 === 0));

Same structure, but the callback returns a boolean and we only include matching elements.

If reduce:

function myReduce(array, reducer, initialValue) {
  let accumulator = initialValue !== undefined ? initialValue : array[0];
  const startIndex = initialValue !== undefined ? 0 : 1;
  for (let i = startIndex; i < array.length; i++) {
    accumulator = reducer(accumulator, array[i], i, array);
  }
  return accumulator;
}

console.log(myReduce([1, 2, 3, 4], (sum, n) => sum + n, 0));
console.log(myReduce([1, 2, 3, 4], (sum, n) => sum + n));

Trickier because of the initial value. The spec says: if an initial value is given, use it and start from index 0. If not, use the first element as the starting accumulator and start from index 1. This is the edge case most candidates miss.

Interactive animation: reduce traced with a seed - each callback return becomes the next accumulator, starting from the initial value.

Debounce: The Senior-Level Question

Debounce comes up in nearly every senior JavaScript interview. Here's the clean implementation:

function debounce(fn, delay) {
  let timeoutId;
  return function(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn.apply(this, args), delay);
  };
}

const log = () => console.log("Search executed");
const debouncedLog = debounce(log, 300);

debouncedLog();
debouncedLog();
debouncedLog();   // Only this last call will actually execute after 300ms

Walk through it:

"Debounce returns a new function that delays calling the original. Every time the new function is called, it clears the previous timer and starts a new one. The original only runs when there's a full delay with no new calls. This is useful for search inputs — you don't want to fire a search on every keystroke."

The interviewer might ask follow-ups: "What if we want to call immediately on the first invocation and debounce the rest?" "How would you cancel a pending debounced call?" These are extensions of the basic pattern.

The Follow-Ups

Interactive animation: The sixty-second round - quick follow-up questions, each answered with the reason behind it.

Interview: What the interviewer asks next.

"What's a higher-order function?" A function that takes a function as an argument, returns a function, or both. Examples: map, filter, debounce.

"What's a pure function?" Same inputs always produce same outputs, no side effects. We covered this in Topic 5.5.

"What's currying?" Transforming a function of multiple arguments into a chain of single-argument functions. add(a, b, c) becomes add(a)(b)(c). Implementation requires nested closures.

"Why use arrow functions for callbacks?" Compact syntax, predictable this binding (inherits from surrounding scope).

"What's the difference between forEach and map?" forEach runs a function for side effects, returns undefined. map transforms each element, returns a new array.

The Founder Moment

Nikhil here. The interview where I really learned this material was actually the System Design round at Google — not a JavaScript round, but the one where they asked me to design a rate limiter. I started talking about throttle and debounce as concepts, and the interviewer asked me to implement them.

I'd implemented debounce dozens of times in production. I knew how it worked. But under pressure, I started overthinking the closure scope of timeoutId and ended up with a bug — I used let timeoutId inside the returned function instead of outside it. The function never debounced anything because each call created a fresh timeoutId.

The interviewer let me run my code, see it fail, and watch me trace through to find the bug. I corrected it within about a minute. Got the offer.

What I took from that: writing the code correctly the first time isn't the win. Catching the bug when you run the code is. Always run your code in interviews when possible. Always trace through edge cases out loud. The interviewer is grading your debugging more than your typing.

Back to JavaScript Basic to Advance