JavaScript Interview Questions & Answers (2026)

JavaScript interviews test the language's three notorious footguns: this-binding, the prototype chain, and the event loop. This guide covers 16 questions we've seen candidates hit at Meta, Google, Stripe, Vercel, Shopify, and startup frontend interviews in the last 12 months. Grouped by difficulty. Frameworks (React, Vue) live in the React-specific guide.

✍️ Miguel Martin, Senior Tech Writer, MiPrep Published Jul 27, 2026 Updated Jul 27, 2026 13 min read 🔒 Private-by-default
Why it matters: JavaScript is unavoidable for any frontend, full-stack, or Node.js backend role. The interviewers are looking for whether you've been burned by the sharp edges (hoisting, this, event-loop starvation) or you'll be burned in production. If you can explain closures without ceremony and reason about microtask vs macrotask ordering, you're already ahead of 70% of candidates.

Beginner questions

1. Explain closures. Beginner

MetaGoogleStripe

A closure is a function bundled with the lexical environment it was declared in. When the inner function survives past the outer function's return, it keeps a reference to the outer function's variables — those variables are not garbage collected. Practical use: private state, memoization, callbacks that need setup context. Common bug: closing over a loop variable declared with var — every closure sees the final value. let fixes it by creating a new binding per iteration.

function counter() {
  let n = 0;
  return () => ++n;
}
const tick = counter();
tick(); tick(); tick(); // 3

2. What's the difference between var, let, and const? Beginner

AmazonMeta

var is function-scoped and hoisted — you can reference it before its declaration and get undefined. let and const are block-scoped and hoisted to the temporal dead zone — referencing them before declaration throws ReferenceError. const binds the identifier immutably but not the value — const arr = []; arr.push(1) is legal.

3. Explain event delegation. Beginner

MetaShopify

Attach one event listener to a parent element instead of many on individual children. Rely on event bubbling — clicks originate at the target, bubble up through ancestors. Use event.target to know which child was clicked. Wins: fewer listeners (memory), works for dynamically-added children (no re-binding), simpler cleanup.

list.addEventListener('click', (e) => {
  const item = e.target.closest('li');
  if (!item) return;
  handle(item.dataset.id);
});

4. What's the difference between == and ===? Beginner

AmazonTCS

=== is strict equality — same type AND same value. == is loose equality — coerces types before comparing, which produces surprises: 0 == '' is true, [] == false is true, null == undefined is true. Always use === unless you specifically want the null-undefined-both-true shortcut, in which case comment it.

5. Explain hoisting. Beginner

AmazonTCS

The JavaScript engine moves declarations to the top of their scope before executing code. var declarations are hoisted with an initial value of undefined. Function declarations are fully hoisted — you can call them before the source line. let and const are hoisted but not initialized — accessing them before the declaration throws. class declarations behave like let.

Practice these live, in your voice

MiPrep's practice mode turns your resume into a rehearsed answer set. Talk through the idioms the way top-tier interviewers score.

Download MiPrep 🔒 Interview audio is never stored on our servers

Intermediate questions

6. How does the event loop work? Intermediate

MetaStripeGoogle

Single-threaded event loop. Sync code runs to completion, then the loop drains the microtask queue (Promise callbacks, queueMicrotask), then processes one macrotask (setTimeout, setInterval, I/O), then drains microtasks again. Rendering happens between macrotasks in the browser. Practical implication: a Promise chain can starve rendering — awaited work stays in microtasks. setTimeout(fn, 0) yields to rendering; Promise.resolve().then(fn) does not.

console.log(1);
setTimeout(() => console.log(2), 0);
Promise.resolve().then(() => console.log(3));
console.log(4);
// Output: 1, 4, 3, 2

7. What is 'this' bound to? Intermediate

MetaGoogle

Four rules, in priority order. (1) new binding — new fn() binds this to the new object. (2) explicit binding — fn.call(x) or fn.bind(x) sets this to x. (3) implicit binding — obj.fn() sets this to obj. (4) default binding — plain fn() gives undefined in strict mode, global in sloppy. Arrow functions have no this of their own — they close over the enclosing this lexically. That's why event handlers written as arrows fail to reference the instance.

8. Explain async/await. Intermediate

StripeMeta

async marks a function as returning a Promise. await suspends the function until the awaited Promise settles, then resumes with the resolved value (or throws the rejection). Under the hood, it's syntactic sugar over Promise.then chains. Common mistake: await in a for-loop when the iterations are independent — use Promise.all for parallel. Correct: await Promise.all(items.map(process)).

// Serial (slow)
for (const url of urls) await fetch(url);

// Parallel (fast)
await Promise.all(urls.map(u => fetch(u)));

9. What is the prototype chain? Intermediate

GoogleMeta

Every object has an internal [[Prototype]] link to another object. Property lookup walks the chain until it finds the property or hits null. class syntax is sugar over prototype-based inheritance. class Dog extends Animal sets Dog.prototype.[[Prototype]] = Animal.prototype. Object.create(proto) creates an object with the given prototype directly.

10. Explain Promise.all vs Promise.allSettled vs Promise.race. Intermediate

MetaStripe

Promise.all — resolves when all resolve, rejects fast on first rejection (short-circuit). Promise.allSettled — waits for every promise regardless of outcome, returns [{status, value|reason}]. Promise.race — resolves/rejects with the first settled promise (fastest, or first failure). Promise.any — resolves with first fulfillment, rejects only if all reject. Choose based on failure semantics: use allSettled for parallel work where partial failure is acceptable.

11. What is a debounce vs a throttle? Intermediate

MetaVercel

Debounce — wait until N ms after the last call, then fire once. Good for search-as-you-type. Throttle — allow at most one call per N ms. Good for scroll handlers. Both use setTimeout / Date.now, but produce different UX. Implement debounce as: return a wrapper that clears the pending timer and sets a new one; throttle as: check timestamp of last call.

12. What is currying? Intermediate

Meta

Transforming a function of N args into a chain of N unary functions. curry(add)(2)(3) === add(2, 3). Useful for partial application and building point-free pipelines. Trivial for fixed arity: const curry = fn => a => b => fn(a, b). Variadic curry is a puzzle interviewer favorite — accumulate args until called with the expected count.

13. How would you deep-clone an object? Intermediate

MetaGoogle

Modern answer: structuredClone(obj) — built into browsers and Node 17+, handles Dates, Maps, Sets, circular refs. JSON.parse(JSON.stringify(obj)) is the interview cliche but silently drops functions, undefined values, Dates (becomes string), Maps, Sets, and throws on cycles. Lodash cloneDeep is fine but ships a dependency. For your interviewer: mention all three, name the tradeoffs.

Advanced questions

14. How does JavaScript handle memory management? Advanced

GoogleMeta

Garbage collection via mark-and-sweep — the GC starts at roots (global object, current stack) and walks references. Unreachable objects are freed. Common leaks: closures holding large objects, forgotten event listeners on removed DOM nodes, growing arrays used as caches without eviction. Use WeakMap / WeakSet for reference-holding without preventing GC. In Node, use --inspect and Chrome DevTools heap snapshots to find retainers.

15. What are ES modules and how do they differ from CommonJS? Advanced

VercelStripe

ESM (import/export) — static, top-level, live bindings. Statically analyzable so bundlers can tree-shake. CommonJS (require/module.exports) — dynamic, runtime evaluation, snapshot semantics (require caches the exported object at the time of first require). Bug pattern: circular imports work in CommonJS (you get a partial object) but break in ESM (you get undefined until initialization completes).

16. What is a Web Worker? Advanced

MetaVercel

A JavaScript execution context on a separate OS thread. Communicates with the main thread via postMessage — arguments are structured-cloned across the boundary (or transferred if using Transferable objects like ArrayBuffer). Use for CPU-bound work (image processing, WASM computation) that would otherwise block rendering. Cannot access DOM. Modern alternative: OffscreenCanvas for graphics workers.

Common mistakes candidates make

  • Forgetting to await a Promise — silently returns the Promise object, later code sees pending state.
  • Mutating props or state directly in React — bypass reactivity.
  • Using == with the intent of ===.
  • Closure over loop variable declared with var — every closure sees the final value.
  • Attaching event listeners without removing them — memory leak in single-page apps.

Study strategy

Two-week plan. Week 1: rebuild Promise, debounce, throttle, curry, and deep-clone from scratch — one per day. Read the ECMA-262 event-loop section (dense but load-bearing). Week 2: 30 medium LeetCode problems tagged JavaScript. In your real interview, when asked 'implement X', write the signature first and check the signature with the interviewer before writing the body.

Do timed mocks with MiPrep before the real thing

Upload your resume and target job description. MiPrep generates a rehearsed answer set in your voice from your own projects — so mock interviews sound like real ones.

Get MiPrep — free 🔒 Interview audio is never stored on our servers