learn deep. ship safe.Practice testsFollow ByteMunSubscribe
JavaScript · Senior

Advanced JavaScript Interview Questions

12 JavaScript interview questions for senior and lead developers (5+ years): the event loop in depth, WeakMap, structuredClone, private fields, prototypes, Symbols, Proxy and memory leaks. Each answer explains why the other options are wrong.

CoversArraysClassesCollectionsCopyingCore JavaScriptEvent loopLoopsMemoryMetaprogrammingObjectsPerformancePrototypesProxySymbols

By Published Answers checked by Deepak

Take it as a timed test

  • 12 questions
  • 18 min
  • Pass mark 60%
  • Answers shown at the end
Start the timed test

No sign-up. Your answers and scores stay in this browser.

This pro paper has 12 JavaScript questions for senior and lead developers with roughly 5+ years of experience. It covers the event loop in depth, WeakMap, structuredClone, private fields, prototypes, Symbols, Proxy and memory leaks. Ten questions are on this page with full explanations; the timed test also includes two questions that aren't shown here, so practise for understanding rather than memory.

How should you use this paper?

Answer each practice question before opening its explanation, and say your reasoning out loud the way you would in an interview. Then take the timed test: 18 minutes, a pass mark of 60%, with answers shown at the end. Your report breaks your score down by topic and difficulty, and you can retry only the questions you missed.

Practice questions with answers

Try each one before opening the answer. The explanation covers why the other options are wrong. The timed test also uses 2 questions that aren't shown here, so practise for understanding, not memory.

Q1What does this code output?hard

In what order do the logs run when a promise callback schedules another timer?

javascript
setTimeout(() => console.log("t1"), 0);
Promise.resolve()
  .then(() => {
    console.log("p1");
    setTimeout(() => console.log("t2"), 0);
  })
  .then(() => console.log("p2"));
console.log("s");
  1. s p1 p2 t1 t2
  2. s p1 t1 p2 t2
  3. s t1 p1 p2 t2
  4. p1 p2 s t1 t2
Show answer and explanation

Answer: A. s p1 p2 t1 t2

The script runs first and logs s. Then the engine drains the microtask queue completely: p1 runs (and queues timer t2 behind t1), and its then queues another microtask that logs p2, which still runs before any timer. Only then do tasks run in the order they were queued: t1, then t2. Microtasks always finish before the next task.

Q2Choose one answermedium

Why would you store per-object metadata in a WeakMap instead of a Map?

  1. A WeakMap doesn't keep its keys alive, so entries disappear when the object is garbage-collected
  2. A WeakMap is faster to iterate
  3. A WeakMap can use strings as keys
  4. A WeakMap is shared across browser tabs
Show answer and explanation

Answer: A. A WeakMap doesn't keep its keys alive, so entries disappear when the object is garbage-collected

A Map holds strong references, so an object used as a key can never be garbage-collected while the map exists, which leaks memory in long-lived caches. WeakMap keys are held weakly: when nothing else references the object, the entry goes away too. The trade-off is that keys must be objects and a WeakMap can't be iterated or sized.

Q3Choose one answermedium

What happens when you run structuredClone({ run() {} })?

  1. It throws a DataCloneError because functions can't be cloned
  2. It returns a copy with the function included
  3. It returns a copy with the function silently removed
  4. It returns the same object
Show answer and explanation

Answer: A. It throws a DataCloneError because functions can't be cloned

structuredClone deep-copies data that can be serialised: objects, arrays, dates, maps, sets, typed arrays and circular references. Functions, DOM nodes and class prototypes can't be cloned, so it throws a DataCloneError rather than dropping them quietly. That's a key difference from JSON.parse(JSON.stringify(x)), which silently omits functions and turns dates into strings.

Q4What does this code output?hard

What does the #x in obj brand check print here?

javascript
class A {
  #x = 1;
  static has(obj) {
    return #x in obj;
  }
}
console.log(A.has(new A()), A.has({}));
  1. true false
  2. true true
  3. false false
  4. It throws a SyntaxError
Show answer and explanation

Answer: A. true false

Private fields are only installed on objects created by the class. #x in obj is an ergonomic brand check: it returns true when the object has that private field and false otherwise, without throwing. An instance of A has #x, a plain object doesn't. It's the safe way to check whether an object really is your class's instance.

Q5Choose one answermedium

A single-page app slowly uses more memory on each route change. What is the most likely cause?

  1. Listeners or intervals that are never removed and keep references to old components
  2. Using const instead of let
  3. Too many CSS classes
  4. Using arrow functions
Show answer and explanation

Answer: A. Listeners or intervals that are never removed and keep references to old components

Each route change mounts new components. If the old ones added window listeners, intervals or subscriptions and never cleaned them up, those callbacks keep their closures, and the DOM and data they reference, alive. Memory grows on every navigation. Remove listeners on unmount and clear timers. Heap snapshots in DevTools, compared before and after navigating, show what is being retained.

Q6What does this code output?medium

What does calling an inherited method and listing own keys print?

javascript
const proto = { greet() { return "hi " + this.name; } };
const o = Object.create(proto);
o.name = "Ana";
console.log(o.greet(), Object.keys(o));
  1. hi Ana ["name"]
  2. hi Ana ["name", "greet"]
  3. hi undefined ["name"]
  4. It throws because o has no greet
Show answer and explanation

Answer: A. hi Ana ["name"]

greet lives on the prototype, so o.greet is found by walking up the prototype chain, and this is o because of how it is called. Object.keys lists only the object's own enumerable properties, so it returns just ["name"]. Methods shared through the prototype don't appear, which is why a for...in loop needs care.

Q7Select all that applymedium

Which statements about Symbol are true? Select all that apply.

  1. Every Symbol() call returns a new, unique value
  2. Symbols can be used as object property keys
  3. Symbol.for('id') returns the same symbol for the same key across the app
  4. JSON.stringify includes symbol-keyed properties
Show answer and explanation

Answer: A. Every Symbol() call returns a new, unique value + B. Symbols can be used as object property keys + C. Symbol.for('id') returns the same symbol for the same key across the app

Each Symbol() is unique, even with the same description, which makes symbols safe keys that can't clash with string keys. Symbol.for uses a global registry, so the same key returns the same symbol. Symbol-keyed properties are skipped by JSON.stringify, Object.keys and for...in; use Object.getOwnPropertySymbols to see them.

Q8True or falsemedium

for...in over an array gives you its values.

TrueFalse

Show answer and explanation

Answer: False

False. for...in loops over enumerable property keys, so for an array you get the indexes as strings ("0", "1"...) and also any enumerable properties added to the array or its prototype. Use for...of for values, or entries() when you need both index and value. for...in is meant for plain objects.

Q9Choose one answermedium

How does queueMicrotask(fn) differ from setTimeout(fn, 0)?

  1. The microtask runs as soon as the current script finishes, before timers and before the browser renders
  2. They are identical
  3. The microtask waits at least 4 ms
  4. The microtask runs in a separate thread
Show answer and explanation

Answer: A. The microtask runs as soon as the current script finishes, before timers and before the browser renders

Microtasks run right after the current call stack empties, before the event loop picks up the next task, so they also run before rendering. setTimeout(fn, 0) queues a task, which runs later, and browsers clamp nested timers to at least 4 ms. A long chain of microtasks can block rendering, so use them for small follow-up work only.

Q10Match each item on the lefthard

Match each Proxy trap to the operation it intercepts.

  1. get
  2. set
  3. has
  4. deleteProperty
  • The delete operator
  • Reading a property
  • The in operator
  • Assigning a property
Show answer and explanation

Answer: get → Reading a propertyset → Assigning a propertyhas → The in operatordeleteProperty → The delete operator

A Proxy wraps an object and lets traps intercept operations on it. get and set handle reads and writes, which is how many reactive state libraries track changes. has intercepts key in obj, and deleteProperty intercepts delete obj.key. Inside traps, Reflect methods perform the default behaviour.

Answered them all? Take the same questions against the clock and get a topic-by-topic report.

Start the timed test

More JavaScript quizzes

All JavaScript quizzes →