Topics in this subject
JavaScript 6 min read Updated 4 Aug 2026

Part 27 — Interview Preparation

Beginner, Intermediate, Advanced, Expert

Scope note. Your spec asked for 300+ questions. Below is a curated, fully-worked bank spanning all four levels — the highest-signal questions that recur across real interviews, each with answer, explanation, code, a common mistake, and follow-ups. Ask me to expand any single tier into its own dedicated question bank and I'll produce it as a follow-up file.

Beginner#

B1. let vs const vs var? Answer: var is function-scoped and hoisted-as-undefined; let/const are block-scoped and in the TDZ until declared; const can't be reassigned (but its object can still be mutated). Common mistake: thinking const makes objects immutable. Follow-up: What's the TDZ?

B2. == vs ===? Answer: == coerces types before comparing; === doesn't. Always prefer ===. Code: 0 == "" // true, 0 === "" // false. Follow-up: When is == null acceptable? (To check null-or-undefined.)

B3. List all falsy values. Answer: false, 0, -0, 0n, "", null, undefined, NaN. Common mistake: thinking [] or "0" is falsy — both are truthy.

B4. null vs undefined? Answer: undefined = not assigned yet (engine default); null = intentional emptiness (you set it). typeof undefined is "undefined"; typeof null is "object".

B5. What is hoisting? Answer: Declarations are processed before execution. var initializes to undefined; function declarations are fully hoisted; let/const are hoisted but unusable until declared (TDZ).

B6. map vs forEach? Answer: map returns a new transformed array; forEach returns undefined and is for side effects. You can't break either; forEach ignores await.

B7. What does typeof return for an array? Answer: "object". Use Array.isArray() to detect arrays.

B8. Difference between slice and splice? Answer: slice(s,e) returns a copied range and doesn't mutate; splice(i,del,...add) mutates and returns removed items.

B9. What's a template literal? Answer: Backtick strings supporting ${expr} interpolation and multiline text.

B10. How do you copy an array? Answer: [...arr], arr.slice(), Array.from(arr) — all shallow copies.

B11. What is NaN and how do you test for it? Answer: "Not-a-Number," result of invalid numeric ops. NaN !== NaN; use Number.isNaN(x).

B12. What is JSON and the two methods you use? Answer: Text data format. JSON.stringify(obj) → string; JSON.parse(str) → value. stringify drops functions/undefined and turns Dates into strings.

Intermediate#

I1. Explain closures with a real use. (Part 9) Answer: A function retaining access to its birthplace's variables. Uses: private state, factories, memoization, event handlers. Follow-up: Why does the var loop print 3,3,3?

I2. The four this binding rules? Answer: new > explicit (call/apply/bind) > implicit (obj.method) > default (undefined/global); arrows use lexical this. Common mistake: assuming this depends on where a function is defined.

I3. call vs apply vs bind? Answer: call(thisArg, ...args) invokes now with listed args; apply(thisArg, argsArray) invokes now with an array; bind returns a new bound function (doesn't invoke).

I4. Event delegation — what and why? Answer: One listener on a parent handles events from many children via bubbling and e.target.closest(). Fewer listeners, works for dynamic children.

I5. Predict the output:

console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D");

Answer: A, D, C, B — sync first, then microtask (C), then macrotask (B).

I6. Promise.all vs allSettled vs race vs any? (see Part 16 table)

I7. Sequential vs parallel awaits — show the fix. Answer: Independent awaits in sequence waste time; use Promise.all([...]) to run them concurrently.

I8. Deep vs shallow copy — three approaches and pitfalls? Answer: spread/Object.assign (shallow), JSON.parse(JSON.stringify) (deep but lossy), structuredClone (correct deep, handles cycles/Map/Set/Date).

I9. Why does 0.1 + 0.2 !== 0.3? Answer: IEEE-754 binary floats can't represent 0.1/0.2 exactly. Compare with Number.EPSILON tolerance.

I10. Implement debounce. (Part 25)

I11. for...in vs for...of? Answer: for...in iterates enumerable keys (incl. inherited); for...of iterates iterable values. Use for...of for arrays.

I12. ESM vs CommonJS? (Part 18 table)

I13. What is a Symbol and where is it used? Answer: Unique primitive used as non-colliding property keys and to customize built-in behaviour (Symbol.iterator).

Advanced#

A1. Explain the event loop, microtasks, and macrotasks in detail. (Part 16) Follow-up: Can microtasks starve macrotasks? (Yes — a microtask that keeps enqueuing microtasks.)

A2. What are hidden classes and inline caches? How do they affect performance? (Part 20)

A3. How does garbage collection work and what causes leaks? (Part 20) Follow-up: When would you use WeakMap/WeakRef?

A4. Implement Promise.all from scratch.

function all(promises) {
  return new Promise((resolve, reject) => {
    const results = []; let done = 0;
    if (promises.length === 0) return resolve(results);
    promises.forEach((p, i) => {
      Promise.resolve(p).then(v => {
        results[i] = v;
        if (++done === promises.length) resolve(results);
      }, reject);
    });
  });
}

A5. Difference between iterator and generator; write an infinite ID generator. (Part 20)

A6. Explain prototypal inheritance and how class maps to it. (Parts 10, 19)

A7. What does new actually do? Answer: Creates an object linked to Fn.prototype, binds this to it, runs the constructor, and returns that object (unless the constructor returns its own object).

function myNew(Ctor, ...args) {
  const obj = Object.create(Ctor.prototype);
  const ret = Ctor.apply(obj, args);
  return (ret && typeof ret === "object") ? ret : obj;
}

A8. Implement bind from scratch.

Function.prototype.myBind = function (ctx, ...bound) {
  const fn = this;
  return function (...args) { return fn.apply(ctx, [...bound, ...args]); };
};

A9. What is currying and how do you implement a generic curry?

const curry = (fn) => function curried(...args) {
  return args.length >= fn.length ? fn(...args) : (...next) => curried(...args, ...next);
};

A10. Explain the difference between Object.freeze (shallow) and true deep immutability, and implement deepFreeze.

function deepFreeze(o) {
  Object.getOwnPropertyNames(o).forEach(k => {
    const v = o[k];
    if (v && typeof v === "object") deepFreeze(v);
  });
  return Object.freeze(o);
}

Expert#

E1. Walk through V8's compilation pipeline (Ignition → TurboFan) and when deopt happens. (Part 1, 20)

E2. Design a rate limiter / token bucket in JS. Discuss timers, precision, and clock drift.

E3. Explain how async/await desugars to promises and generators, and the exact scheduling of await continuations (microtask).

E4. How would you find and fix a memory leak in a long-running SPA? Heap snapshots, retained-size analysis, detached nodes, listener/timer cleanup, WeakMap caches.

E5. Implement an LRU cache in O(1) using Map (insertion order + delete/re-set trick).

class LRU {
  constructor(cap){ this.cap = cap; this.map = new Map(); }
  get(k){ if(!this.map.has(k)) return; const v=this.map.get(k); this.map.delete(k); this.map.set(k,v); return v; }
  set(k,v){ if(this.map.has(k)) this.map.delete(k); this.map.set(k,v); if(this.map.size>this.cap) this.map.delete(this.map.keys().next().value); }
}

E6. Explain proper tail calls, why V8 lacks them, and how you'd handle deep recursion (trampolining).

E7. How do Proxies power reactive frameworks (Vue 3)? What are the pitfalls (identity, this, performance)?

E8. Explain the difference between structural typing (TS) and JS's runtime prototype checks; where does instanceof fail (cross-realm)?