Utilities From Scratch
In one line
A short list of utilities — debounce, throttle, memoize, bind, Promise.all, deep clone, curry, event emitter — covers most 45-minute JavaScript screens, and each one is a proxy for a concept.
What it is
The technical screen at these companies is live coding in a shared editor: roughly 45 minutes, one or two problems, usually a utility or a small UI behaviour rather than an algorithm. The set of utilities in rotation is small and stable, and each is chosen because it can't be written without understanding something specific.
debounce tests closures and timer handling. The naive version is five lines; the follow-ups are where it's scored — a cancel method, a leading/trailing option, preserving this and arguments, and returning the last result. throttle is the sibling, and being able to state the difference crisply (debounce waits for quiet, throttle guarantees a rate) matters more than either implementation.
memoize tests closures plus cache-key design. The interesting question is never the Map — it's how you key on arbitrary arguments, and whether you notice that JSON.stringify as a key is wrong for objects with different insertion order and impossible for functions. WeakMap for single-object arguments is the answer that stands out.
bind tests this precedence directly. A correct implementation handles partial application, and the new case — a bound function used as a constructor ignores the bound this. Almost nobody handles that unprompted; mentioning it is free signal.
Promise.all tests the promise model: resolve order must follow input order, not completion order; the count of settled promises is what decides completion; a single rejection settles the outer promise immediately; and an empty array resolves immediately. allSettled and race are natural follow-ups. Building a minimal promise from scratch is the harder variant and is genuinely worth doing once against the Promises/A+ spec.
Deep clone tests recursion plus edge cases: cycles (needs a WeakMap of seen objects), Date, Map, Set, and knowing that structuredClone exists and what it can't handle. Saying "in production I'd use structuredClone, but here's the implementation" is the right framing.
Event emitter (on/off/emit/once) tests data-structure choice and the subtle bug: removing a listener during emit while iterating the same array. Copying the listener array before iterating is the fix.
The meta-skill matters as much as the code. Clarify requirements before typing, state the approach out loud, write it, then volunteer the edge cases and the test you'd add. Interviewers score communication and edge-case awareness explicitly — a working solution delivered in silence scores below a slightly rougher one that was reasoned through aloud.
Why it matters
This is the round that gates everything after it, and it is the most preparable part of the entire loop — the question set barely changes. Practising these until they're automatic frees your attention during the interview for the part that's actually being assessed: how you think and how you communicate.
Each one also doubles as a check on the rest of this subsection. If debounce is awkward, closures need another pass; if bind is awkward, so does this.
Key points
- Debounce waits for a quiet period before firing; throttle guarantees a maximum rate. Being able to state the difference in one sentence is scored before either implementation is.
- Every one of these utilities must forward
thisand all arguments to the wrapped function, which is why they are written withfunctionrather than arrow syntax. memoizeis a cache-key problem, not a cache problem —JSON.stringifyfails on key order and functions, andWeakMapis the right structure for single-object arguments.- A correct
bindhandles partial application and thenewcase, where the boundthisis ignored in favour of the newly constructed object. Promise.allmust preserve input order in its results, track a settled count rather than relying on the last resolution, reject on the first failure, and resolve immediately for an empty array.- Deep clone needs a
WeakMapof visited objects to survive cycles; namestructuredCloneas the production answer before writing the manual one. - An event emitter must copy its listener array before iterating in
emit, or removing a listener from within a handler corrupts the iteration. - Clarify requirements, narrate the approach, then volunteer edge cases — communication is explicitly scored, and silence costs more than an imperfect first attempt.