JavaScript Interview Questions: 5 Worked Problems by Topic

Five problems across the four areas front-end interviews keep returning to. Each group opens with the rule that answers the whole family of questions, then gives you code to trace before the explanation.

JavaScript interviews reuse a small set of questions because a handful of rules explain almost every surprising output: scope and hoisting, how this is bound at call time, the microtask-before-macrotask ordering of the event loop, and coercion under ==.

The value is not in memorising the outputs — it is that each rule collapses a whole family of questions into one sentence. Once you can say 'let creates a fresh binding per iteration,' the loop question, the IIFE follow-up and the closure question all have the same answer.

Trace each snippet before opening the explanation. Every explanation names the follow-up that usually comes next, because the first correct answer only earns you the harder version.

Four areas, five problems

var, let and the closure-in-a-loop classic

1 problem

The honest answer is one word — scope — but the interviewer wants the consequence. var is function-scoped and hoisted (initialised to undefined), let is block-scoped and sits in the temporal dead zone until its declaration runs. That difference is the entire reason the loop-with-setTimeout question has two different answers depending on which keyword you used, and that question is asked in roughly every front-end interview.

How it gets asked: "What is the difference between var and let?" · "Why does this loop log 3, 3, 3?"

Q1

What does each loop log?

for (var i = 0; i < 3; i++) setTimeout(() => console.log(i));
for (let j = 0; j < 3; j++) setTimeout(() => console.log(j));
  1. A0 1 2 then 0 1 2
  2. B3 3 3 then 0 1 2
  3. C0 1 2 then 3 3 3
  4. D3 3 3 then 3 3 3
Show answer & explanation

Answer: B. 3 3 3 then 0 1 2

🐱 var i is one binding shared by all three callbacks; by the time the timers fire the loop has finished and i is 3. let j creates a fresh binding per iteration, so each callback closes over its own value. The follow-up they ask next is how you would fix the var version without changing the keyword — an IIFE per iteration, (function(i){ setTimeout(() => console.log(i)); })(i), which is the pre-ES6 idiom this feature replaced.

this: the four binding rules

1 problem

this is decided at call time by how the function is called, not where it is defined — with one exception that makes the whole topic answerable. In order of precedence: new binds this to the new object; explicit call/apply/bind binds what you pass; a method call binds the object before the dot; otherwise it is undefined in strict mode (or the global object outside it). The exception: arrow functions have no this of their own and inherit it lexically, which is why they fixed the const self = this era.

How it gets asked: "What is this here?" · "Why do arrow functions behave differently?"

Q2

What does this log?

const obj = {
  name: 'cat',
  regular() { return this.name; },
  arrow: () => this?.name,
};
console.log(obj.regular(), obj.arrow());
  1. A'cat' 'cat'
  2. B'cat' undefined
  3. Cundefined 'cat'
  4. DIt throws a TypeError
Show answer & explanation

Answer: B. 'cat' undefined

🐱 regular is called as a method, so this is obj and it returns 'cat'. arrow was defined in the enclosing scope — an object literal creates no scope — so its this is whatever the surrounding scope had (module scope: undefined), giving undefined. The rule to state: never use an arrow function for a method that needs this; do use one for a callback inside a method, which is exactly where the lexical binding helps.

The event loop: why order surprises people

1 problem

One rule answers most of these: synchronous code runs to completion first, then all pending microtasks (promise callbacks, queueMicrotask), then one macrotask (setTimeout, I/O) — and after each macrotask the microtask queue is drained again. So a .then always beats a setTimeout(…, 0) scheduled at the same moment, no matter how the code is ordered on the page.

How it gets asked: "What order does this print?" · "Difference between a microtask and a macrotask?"

Q3

What is the output order?

console.log('A');
setTimeout(() => console.log('B'));
Promise.resolve().then(() => console.log('C'));
console.log('D');
  1. AA B C D
  2. BA D C B
  3. CA D B C
  4. DA C D B
Show answer & explanation

Answer: B. A D C B

🐱 Synchronous first: A, D. Then the microtask queue: C. Then the macrotask: B. The answer A D C B is the canonical demonstration that promises are not just 'faster timers' — they run in a different queue that is drained before any timer gets a turn. The follow-up is usually async/await: an await splits the function and resumes as a microtask, so it behaves like .then for ordering purposes.

== vs === and the coercion questions

1 problem

=== compares type and value with no conversion; == converts first, following rules almost nobody memorises correctly. The professional answer is not to recite the coercion table but to state the policy: always use ===, with the single idiomatic exception x == null, which checks null and undefined at once. Interviewers asking [] == false are usually testing whether you know to avoid the situation, not whether you can trace the spec.

How it gets asked: "Difference between == and ===?" · "Why is [] == false true?"

Q4

Which comparison is the one idiomatic use of == in modern JavaScript?

  1. Ax == 0 to catch empty strings too
  2. Bx == null, which is true for both null and undefined
  3. Cx == false to test falsiness
  4. DNone; == is deprecated
Show answer & explanation

Answer: B. x == null, which is true for both null and undefined

🐱 x == null is the accepted exception because it concisely covers null and undefined and nothing else — many style guides allow exactly this one. The others are traps: '' == 0 is true, [] == false is true, and relying on either produces bugs that survive code review because they look intentional. == is not deprecated, just avoided.

Keep going

JavaScript interview questions — FAQ

What are the most common JavaScript interview questions?

var vs let (and the setTimeout loop), how this is bound, the event loop's microtask/macrotask order, == vs ===, closures, and prototypal inheritance. The first four are on this page; closures appear inside the scope section.

How much event-loop detail do I need?

Enough to predict output: sync code, then all microtasks, then one macrotask, repeating. Naming the queues and predicting an ordering correctly is usually the whole ask at anything below senior level.

Should I say 'never use =='?

Say 'use === everywhere, with x == null as the one exception.' That reads as having a policy rather than a memorised table, which is what the question is really probing.

Are these real interview questions?

They are original problems written around the concepts interviews repeatedly test, not transcripts from any company's process.