JavaScript interview questions (2026)

Language fundamentals, async behavior and practical bugs, checked against current ECMAScript and Node.

These JavaScript interview questions cover the language itself: the event loop, scope, this, promises, modules and the newer built-ins from ES2023 through ES2025. They work for frontend and Node roles alike, and for candidates who want to know which details interviewers really check. Each question includes what a good answer covers and, where useful, a red flag. Choose 6 to 8, mix fundamentals with at least one practical bug, and always ask the candidate to explain their reasoning out loud.

What a strong JavaScript interview checks

  • Execution model: the call stack, task queue and microtask queue.
  • Scope and binding: closures, hoisting, block scope and how this is set.
  • Async fluency: promises, async and await, and error handling.
  • Data handling: equality, copying, numbers and modern array and set methods.
  • Debugging instinct: finding leaks, precision errors and environment-specific bugs.

JavaScript interview questions: fundamentals

1. In what order do these log: console.log('a'), a setTimeout of 0 logging 'b', Promise.resolve().then logging 'c', then console.log('d')?

What good looks like: a, d, c, b. Synchronous code runs first. When the stack is empty, the microtask queue (promise callbacks) drains completely before the next task (the timer callback) runs. A strong answer adds that await continuations are also microtasks, and that a timer of 0 means "as soon as possible after this," not "now."

Red flag: assuming setTimeout 0 runs before promise callbacks.

2. A loop with var i schedules three timeouts that log i. Why does it print 3, 3, 3, and how do you fix it?

What good looks like: var is function-scoped, so all three callbacks close over one shared i, which is 3 by the time they run. Using let creates a fresh binding per iteration, so it prints 0, 1, 2. This is a clean test of whether the candidate understands closures as references to variables, not copies of values.

3. Compare var, let and const.

What good looks like: var is function-scoped and hoisted with a value of undefined. let and const are block-scoped and hoisted into a temporal dead zone, so using them before the declaration throws a ReferenceError. const prevents reassignment, not mutation: a const object's properties can still change. Object.freeze is shallow.

4. How is the value of this decided?

What good looks like: by how the function is called. As a method, this is the object before the dot. As a plain call, it's undefined in strict mode (and in modules and classes) or the global object in sloppy mode. With new, it's the new instance. call, apply and bind set it explicitly. Arrow functions don't have their own this; they use the surrounding one, which is why they suit callbacks inside methods.

Red flag: passing obj.method as a callback and being surprised that this is lost.

5. When, if ever, would you use == instead of ===?

What good looks like: === compares without type coercion and should be the default. == converts types first, which produces surprises like '' == 0 being true. The one common, deliberate use is x == null, which matches both null and undefined.

6. How does prototypal inheritance relate to class syntax?

What good looks like: every object has a prototype, and property lookups walk up that chain until they find a match or reach null. class is mostly syntax over this system: methods live on the prototype, and extends links the prototypes. Classes add real features too, such as private #fields and static blocks.

7. What is the difference between ?? and ||?

What good looks like: a || b falls back to b for any falsy a, including 0, an empty string and false. a ?? b falls back only when a is null or undefined. For a setting where 0 is valid, || is a bug. Optional chaining (user?.address?.city) pairs naturally with ??.

8. How do you copy an object, and what does each method miss?

What good looks like: spread ({ ...obj }) and Object.assign are shallow, so nested objects are shared. JSON.parse(JSON.stringify(obj)) drops functions and undefined, turns Dates into strings, and fails on cycles. structuredClone makes a deep copy that handles Dates, Maps, Sets and cycles, but it can't clone functions or DOM nodes, and class instances come back as plain objects.

9. Which newer built-ins do you use, and why?

What good looks like: toSorted, toReversed, toSpliced and with (ES2023) return new arrays, unlike sort and reverse, which mutate in place. Object.groupBy and Promise.withResolvers arrived in ES2024. ES2025 added Set methods such as union and intersection, and iterator helpers like map and take on iterators. A strong candidate checks runtime support before relying on them.

Async JavaScript

10. Explain Promise.all, allSettled, any and race.

What good looks like: all resolves with every result, or rejects on the first rejection. allSettled waits for everything and reports each outcome. any resolves with the first success and rejects only if all fail, with an AggregateError. race settles with whichever settles first, success or failure. Example: use allSettled for a dashboard where one failed widget shouldn't blank the page.

11. Why does using await inside array.forEach not wait?

What good looks like: forEach ignores the promises its callback returns, so the loop finishes immediately. For sequential work, use for...of with await. For parallel work, use await Promise.all(items.map(fn)), with a concurrency cap if the list is large.

12. How do errors flow through async functions?

What good looks like: a thrown error inside an async function rejects its promise, and try and catch around an await catches it. A missing await means the catch never sees the error. Inside a try block, return await promise differs from return promise, because only the first lets the catch handle a rejection. Unhandled rejections crash Node processes by default.

13. What is the difference between ES modules and CommonJS?

What good looks like: ES modules use static import and export, which tools can analyze for tree shaking. Imports are live bindings, and ESM supports top-level await. CommonJS uses require, which loads synchronously and returns a copy of module.exports. Recent Node versions can require() an ES module as long as it doesn't use top-level await, which has eased mixing the two.

Practical scenarios

14. Write a debounce function and explain how it works.

What good looks like: return a function that clears a stored timer and sets a new one on every call, running the original only after calls stop for the given delay. The timer ID lives in a closure. Strong answers forward arguments and this, and mention options like running on the leading edge or a cancel method.

15. A dashboard tab gets slower the longer it stays open. How do you find the leak?

What good looks like: take heap snapshots in browser DevTools a few minutes apart and compare what grows. Common causes are event listeners never removed, intervals never cleared, detached DOM nodes still referenced, and caches with no limit. Fixes include removing listeners with an AbortController signal, clearing timers on teardown, and using WeakMap for per-object metadata.

16. Why is 0.1 + 0.2 not equal to 0.3, and how do you handle money?

What good looks like: numbers are 64-bit binary floating point, which can't represent 0.1 exactly. For money, store integer cents (or use BigInt or a decimal library), and format for display with Intl.NumberFormat. For comparing floats, check that the difference is within a small tolerance.

Red flag: "Just round it with toFixed" as the whole answer.

17. Write a fetch helper with a timeout and retries.

What good looks like: pass AbortSignal.timeout(ms) as the signal, and remember that fetch only rejects on network failure, so check response.ok for 4xx and 5xx statuses. Retry only on errors worth retrying (timeouts, 5xx, 429), use exponential backoff with some randomness, and cap the attempts.

18. An API returns an ID like 9007199254740993, but your app shows ...992. What happened?

What good looks like: JSON.parse turns it into a Number, and integers above Number.MAX_SAFE_INTEGER (2 to the 53rd power minus 1) lose precision. The fix is for the API to send large IDs as strings, or, in runtimes that expose the original source text to JSON.parse revivers, to convert it to BigInt there.

Behavioral (STAR)

19. Tell me about a bug that only happened in one browser or environment.

What good looks like: how they reproduced it, how they narrowed the cause (feature support, timing, a polyfill, a time zone), the fix, and what they added to stop it returning, such as a test in that environment.

20. Describe a time you removed or replaced a dependency.

What good looks like: a reason grounded in evidence (bundle size, security advisories, maintenance), a safe migration plan, and a measurable Result. Strong candidates weigh the cost of writing code themselves against keeping the package.

A simple scoring rubric

ScoreWhat you hear
1Guesses on the event loop and this. Can't explain closures or why async code runs out of order.
2Gets the definitions right but struggles with the practical bugs, such as the forEach or precision questions.
3Correct, clear answers with real examples, and knows which modern built-ins exist and when they help.
4A 3, plus edge cases, runtime differences and debugging methods offered unprompted, explained well enough to teach.

Running this interview with AI

JavaScript is one of the languages in NTRVSTA's exam library. The AI interviewer runs a live conversation, by audio or video avatar, and moves difficulty up or down with each answer. Someone who explains the microtask queue clearly gets pushed toward async error handling and leaks. Someone who stumbles gets a gentler path and, if you allow it, a hint, so you can see how they reason with a little help.

Afterwards you get a score breakdown and video snippets of the strongest and weakest moments, which makes calibration across interviewers easier. Our guide to how AI interviews are scored explains what to check before trusting a number, and the best AI interview software compares tools honestly. For related roles, see React, Node.js and frontend developer questions.

Questions

Should JavaScript interviews include TypeScript questions?

If the team writes TypeScript, add two or three, such as the difference between a type and an interface or how narrowing works. Keep the core on JavaScript itself, since TypeScript's types disappear at runtime and the bugs on this page still happen.

Are output-prediction questions fair?

One or two are fine when they test something that causes real bugs, like microtask order or closures in loops. A whole round of trick questions rewards memorization. Always ask the candidate to explain why, not just give the output.

How much browser versus Node knowledge should I expect?

Match the role. A frontend hire should know the DOM, events and browser storage. A backend hire should know modules, streams and the Node event loop. The language questions here apply to both.

Screening JavaScript developers at volume? Book a 20-minute demo to see a live adaptive round, or take a sample interview to feel it from the candidate's side.

NTRVSTA
‍