Interview guide
JavaScript Developer Interview Questions & Answers Guide (2026)
A hiring-manager’s interview kit for javascript developers — with specific “what to look for” notes on every answer, red flags to watch, and a practical test.
Interviewing a JavaScript Developer? This guide gives you 26 real interview questions — 14 technical (tagged easy, medium, and hard), 7 behavioral, and 5 role-fit — each with a specific “what to look for” scoring rubric, 8 red flags to reject on, and a hands-on practical test, so you hire on demonstrated evidence, not a confident-sounding résumé.
Key facts
- Role
- JavaScript Developer
- Technical questions
- 14
- Behavioral
- 7
- Role-fit
- 5
- Red flags
- 8
- Practical test
- Included
How to use this guide
Pick 4-6 technical questions across difficulties, 2-3 behavioral, and 1-2 role-fit for a 45-minute interview. For senior roles, weight harder technical and role-fit higher. Always close with the practical test so you are hiring on evidence, not impressions. The “what to look for” notes are a scoring rubric: strong answers touch most points, weak answers miss them or replace them with platitudes.
Technical questions — Easy
1. What is a closure, and give a concrete example where one caused a bug you had to fix.
EasyWhat to look for: Correct definition — a function retaining access to its lexical scope after the outer function returns. Bonus for a real bug: a stale value captured in a loop with var, or a closure holding a large object and leaking memory. Red flag: reciting the definition with no lived example.
2. Explain the difference between == and ===, and describe a real coercion gotcha you have hit.
EasyWhat to look for: Loose equality applies type coercion with the abstract equality algorithm; strict does not. Gotchas: null == undefined, [] == false, NaN !== NaN. Should default to === and know why.
3. Explain the temporal dead zone and how let, const, and var differ in hoisting and scope.
EasyWhat to look for: var is function-scoped and hoisted with undefined; let/const are block-scoped and hoisted but not initialized (the TDZ) until the declaration. const binds, it does not deep-freeze. Should know why var in loops with closures misbehaves.
Technical questions — Medium
1. Explain the prototype chain. How does inheritance actually work in JavaScript, and how does class relate to it?
MediumWhat to look for: Objects delegate to their prototype via [[Prototype]] / __proto__; property lookup walks the chain. class is syntax over prototype-based inheritance, not a new model. Bonus: Object.create, and why extending built-ins is risky.
2. Walk me through the output order of a snippet that mixes synchronous code, setTimeout, and a resolved Promise.then. Why does it come out that way?
MediumWhat to look for: Call stack first, then microtask queue (promises), then macrotask queue (timers). Should say microtasks drain fully before the next macrotask. This is the single best filter for real event-loop understanding.
3. How does this binding work? Contrast a regular function, an arrow function, a method call, and call/apply/bind.
MediumWhat to look for: Regular functions bind this at call time (or undefined in strict mode); arrows capture lexical this; method calls bind to the object left of the dot; call/apply/bind set it explicitly. Should know arrows have no own this and cannot be rebound.
4. You have three async operations. Contrast Promise.all, Promise.allSettled, and Promise.race, and when you would reach for each.
MediumWhat to look for: all rejects on first failure; allSettled waits for all and reports each outcome; race settles on the first to settle. Bonus: Promise.any, and using allSettled when partial failure is acceptable. Should discuss error handling and not swallowing rejections.
5. What are ES modules, and how do they differ from CommonJS? What breaks when you mix them?
MediumWhat to look for: import/export vs require/module.exports; ESM is static and async-loaded with live bindings, CJS is dynamic and synchronous. Mixing causes interop headaches (default export shape, __dirname, top-level await). Bonus: tree-shaking depends on static ESM.
6. How would you cancel an in-flight fetch when a component unmounts or the user types a new search query?
MediumWhat to look for: AbortController and passing signal to fetch, aborting the previous request on a new one. Should mention handling the AbortError and debouncing the input. Red flag: setting an ignore flag but leaving the request running.
7. Write a debounce function. Then tell me how throttle differs and when you would pick each.
MediumWhat to look for: Correct debounce: clears and resets a timer, returns a wrapped function, handles arguments/this. Throttle fires at most once per interval. Debounce for search input; throttle for scroll/resize. Bonus: leading/trailing options and cleanup.
8. How do you narrow a TypeScript discriminated union, and why is it better than a bag of optional fields?
MediumWhat to look for: A shared literal tag field lets the compiler narrow in a switch/if so only valid fields are accessible per variant. Beats optional fields because it makes illegal states unrepresentable. Bonus: exhaustiveness checks with never.
9. What is the difference between shallow and deep copying an object, and how do you correctly deep-clone a value with nested arrays and dates?
MediumWhat to look for: Spread/Object.assign copy one level; nested references are shared. structuredClone handles most cases (including dates, maps, cycles) but not functions/DOM nodes. Should know JSON.parse(JSON.stringify(...)) drops undefined, functions, and mangles dates.
Technical questions — Hard
1. What is the difference between the microtask and macrotask queues, and when does that difference bite you in production?
HardWhat to look for: Promises/queueMicrotask vs setTimeout/setInterval/I-O. Bites you when a promise chain starves rendering, or when ordering assumptions between a timer and a promise break. Bonus: how await desugars to .then microtasks.
2. Describe a memory leak you have diagnosed in a JavaScript app. How did you find it and what caused it?
HardWhat to look for: Real story: detached DOM nodes, forgotten event listeners or intervals, closures holding large objects, growing caches without eviction. Tools: Chrome heap snapshots, allocation timeline, Node --inspect. Red flag: has never thought about leaks.
Behavioral questions
1. Tell me about a time you chose plain JavaScript over adding a framework or library. How did you make the call?
What to look for: Weighed bundle cost, maintenance, and team familiarity against the benefit; did not add a dependency for something a few lines could do. Shows judgment, not dogma.
2. Describe the worst async bug you shipped and what you learned.
What to look for: Takes ownership, explains root cause (race condition, unhandled rejection, ordering assumption), and the guardrail added after — a test, a lint rule, or a pattern change.
3. How do you keep your code review comments useful without coming across as pedantic?
What to look for: Separates blockers from suggestions, explains the why, praises good choices, asks questions rather than issuing decrees.
4. Walk me through how you onboard yourself into an unfamiliar JavaScript codebase.
What to look for: Runs it locally, traces one user flow end to end, reads the build config, opens a small PR early to validate understanding.
5. What is the most technically demanding thing you have shipped in JavaScript, and why was it hard?
What to look for: Specific dimensions of difficulty — scale, ambiguity, performance, or novel tech. Shows depth and taste, not just feature count.
6. How do you work a full day with only about an hour of overlap with a US team?
What to look for: Batches questions, writes thorough PR descriptions, records short walkthroughs, protects the overlap hour for blocking issues. Demonstrates async discipline.
7. When have you pushed back on a deadline, and how did you frame it?
What to look for: Offers a trade-off across scope, quality, and time rather than a flat no. Communicates early, not at the deadline.
Role-fit questions
1. You will move between browser and Node work rather than staying in one framework. How do you feel about that breadth?
What to look for: Energized by range, comfortable context-switching, honest about which side they are stronger on. Red flag: only wants to live inside one framework.
2. Our stack is TypeScript across a Node API and a React front end. What there have you not used, and how would you ramp up?
What to look for: Honest gap assessment plus a concrete ramp plan (docs, a small spike, pairing). Fakery is the red flag.
3. How do you decide when a piece of work justifies pulling in a new dependency?
What to look for: Weighs maintenance, bundle size, and security surface against a few lines of own code; checks what is already installed first. Not reflexively adding or reflexively refusing.
4. What does the first 30 days look like for you to feel productive in this role?
What to look for: Codebase tour, a small PR in week 1, owning a feature by week 2, asking to pair. Red flag: expects weeks of onboarding with no output.
5. Where are you on pragmatism versus purism when a trade-off comes up on a deadline?
What to look for: Names the trade-off, picks pragmatism with a follow-up ticket for the debt, and holds the line where it matters (security, correctness, accessibility).
Red flags
Any one of these alone is usually reason to pass, especially combined with weak answers elsewhere.
- • Cannot explain a closure or gives a memorized definition with no real example.
- • Gets the output order of a promise-vs-setTimeout snippet wrong and cannot reason about why.
- • Thinks class introduces classical inheritance and does not know the prototype chain underneath.
- • Only works inside one framework and freezes on plain JavaScript or DOM questions.
- • Uses "any" casually in TypeScript and shrugs when asked why.
- • Leaves promise rejections unhandled and cannot describe how they debug async bugs.
- • Reaches for a new dependency before considering a few lines of their own code.
- • Copies code from Stack Overflow into a live exercise without reading it.
Practical test
4-hour take-home: build a small typeahead search that fetches from a mock API. Requirements in vanilla TypeScript (no UI framework): debounced input, cancellation of stale requests with AbortController, loading and error states, keyboard navigation of results, and at least 3 Vitest tests covering the happy path and one error case. We grade on: correctness and async handling (40%), code quality and types (30%), edge cases like empty and error states (20%), and tests (10%). Bonus points for handling the out-of-order-response race and for a clean module boundary between fetch logic and DOM rendering.
Scoring rubric
Score each answer 1-4: (1) Misses most of the rubric or gives platitudes; (2) Hits some points but cannot go deep when pressed; (3) Covers the rubric and can defend the answer under follow-ups; (4) Adds unprompted nuance, trade-offs, or real examples beyond the rubric. Hire at an average of 3.0+ across technical, behavioral, and role-fit, with zero red flags, and a pass on the practical test.
Skip the interview grind — hire a pre-vetted JavaScript Developer
We run this exact vetting process for you. Tell us the role and we’ll send 3 pre-vetted javascript developers within 5 business days — from $2600/mo, with a 30-day replacement guarantee.
Related
Written by Syed Ali
Founder, Remoteria
Syed Ali founded Remoteria after a decade building distributed teams across 4 continents. He helps US businesses source, vet, onboard, and scale pre-vetted offshore talent in engineering, design, marketing, and operations.
- • 10+ years building distributed remote teams
- • Direct hiring experience across US, UK, EU, and APAC markets
- • Specialist in offshore vetting and cross-timezone team integration
Last updated: April 12, 2026