๐ŸŒ Detecting your locationโ€ฆ

JavaScript Interview Questions 2026: Closures, Event Loop and ES2024

โฑ๏ธ5 min read  ยท  991 words

JavaScript interview questions in 2026 cover closures, promises, the event loop, modern ES2022+ features, TypeScript, and React patterns. This guide covers the most frequently asked questions at top tech companies with clear code examples.

Core JavaScript Questions

1. Explain closures with a practical example

// Closure = function that remembers its outer scope
function counter(start = 0) {
  let count = start; // outer variable

  return {
    increment: () => ++count,
    decrement: () => --count,
    value: () => count,
    reset: () => { count = start; }
  };
}

const c = counter(10);
console.log(c.increment()); // 11
console.log(c.increment()); // 12
console.log(c.value());     // 12
c.reset();
console.log(c.value());     // 10

// Practical use: memoization
function memoize(fn) {
  const cache = new Map();
  return function(...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) return cache.get(key);
    const result = fn.apply(this, args);
    cache.set(key, result);
    return result;
  };
}

const expensiveFn = memoize((n) => n * n);
console.log(expensiveFn(5));  // computed
console.log(expensiveFn(5));  // cached

2. What is the event loop?

// JavaScript is single-threaded, but handles async via event loop

console.log("1 - synchronous");          // runs first

setTimeout(() => console.log("2 - macro-task"), 0);  // queued in macro-task queue

Promise.resolve().then(() => console.log("3 - micro-task"));  // micro-task queue

console.log("4 - synchronous");          // runs before any async

// Output order:
// 1 - synchronous
// 4 - synchronous
// 3 - micro-task    (micro-tasks run before macro-tasks!)
// 2 - macro-task

// Event loop order:
// 1. Execute all synchronous code
// 2. Process all micro-tasks (Promises, queueMicrotask)
// 3. Pick one macro-task (setTimeout, setInterval, I/O)
// 4. Repeat

3. Explain var vs let vs const

// var โ€” function scope, hoisted, can redeclare
function example() {
  console.log(x); // undefined (hoisted)
  var x = 1;
  if (true) {
    var x = 2; // same x (function scope)
  }
  console.log(x); // 2
}

// let โ€” block scope, temporal dead zone, can reassign
{
  // console.log(y); // ReferenceError (TDZ)
  let y = 1;
  if (true) {
    let y = 2; // different y (block scope)
    console.log(y); // 2
  }
  console.log(y); // 1
}

// const โ€” block scope, cannot reassign (but objects are mutable)
const arr = [1, 2, 3];
arr.push(4); // OK โ€” mutating object, not reassigning reference
// arr = []; // TypeError โ€” cannot reassign

4. What is prototypal inheritance?

// Every object has a [[Prototype]] (accessed via __proto__ or Object.getPrototypeOf)
const animal = {
  speak() { return `${this.name} makes a sound`; }
};

const dog = Object.create(animal);
dog.name = 'Rex';
console.log(dog.speak()); // "Rex makes a sound" โ€” inherited!

// Class syntax (syntactic sugar over prototypes)
class Animal {
  constructor(name) { this.name = name; }
  speak() { return `${this.name} makes a sound`; }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }
  speak() { return `${this.name} barks`; }
}

const d = new Dog('Rex', 'Labrador');
console.log(d.speak());            // "Rex barks"
console.log(d instanceof Dog);     // true
console.log(d instanceof Animal);  // true

Async JavaScript

5. Promise.all vs Promise.allSettled vs Promise.race vs Promise.any

const p1 = fetch('/api/users');
const p2 = fetch('/api/posts');
const p3 = fetch('/api/missing');  // will fail

// Promise.all โ€” fails if ANY fails
const [users, posts] = await Promise.all([p1, p2]);  // throws if p3 fails

// Promise.allSettled โ€” waits for all, doesn't fail
const results = await Promise.allSettled([p1, p2, p3]);
results.forEach(r => {
  if (r.status === 'fulfilled') processData(r.value);
  else console.error(r.reason);
});

// Promise.race โ€” resolves/rejects with FIRST settled
const fastest = await Promise.race([p1, p2]);  // whichever resolves first

// Promise.any โ€” resolves with FIRST fulfilled (ignores rejections)
const first = await Promise.any([p1, p2, p3]);  // first success

6. What are WeakMap and WeakSet used for?

// WeakMap โ€” keys are objects, garbage collected when object is unreachable
const cache = new WeakMap();

function processData(obj) {
  if (cache.has(obj)) return cache.get(obj);
  const result = heavyComputation(obj);
  cache.set(obj, result);  // obj can still be GC'd
  return result;
}

// WeakSet โ€” stores object references, auto-cleaned
const seen = new WeakSet();

function markAsSeen(obj) {
  seen.add(obj);
}

// Key: WeakMap/WeakSet don't prevent garbage collection
// Perfect for: private data, caching with automatic cleanup, tracking objects

Modern JavaScript (ES2020-2024)

7. Optional chaining (?.) and nullish coalescing (??)

const user = { profile: { name: "Alice" } };

// Optional chaining โ€” stop chain on null/undefined
const name = user?.profile?.name;       // "Alice"
const city = user?.address?.city;       // undefined (no error!)
const len = user?.profile?.name?.length; // 5

// Method calls
const result = user?.getProfile?.();    // undefined if method doesn't exist

// Array access
const first = arr?.[0];                 // undefined if arr is null

// Nullish coalescing โ€” default for null/undefined only
const displayName = user?.name ?? "Anonymous";  // "Anonymous"
const count = 0 ?? 10;   // 0 (0 is not null/undefined)
const count2 = 0 || 10;  // 10 (0 is falsy โ€” different behavior!)

// Nullish assignment
user.name ??= "Default";  // assign only if null/undefined

8. What are WeakRef and FinalizationRegistry?

// WeakRef โ€” hold weak reference to object (allows GC)
let obj = { data: "important" };
const ref = new WeakRef(obj);

// Later...
const deref = ref.deref();
if (deref) {
  console.log(deref.data); // might be undefined if GC'd
}

// FinalizationRegistry โ€” callback when object is GC'd
const registry = new FinalizationRegistry((heldValue) => {
  console.log(`Cleaned up: ${heldValue}`);
  // Clean up external resources associated with obj
});

let obj2 = { data: "value" };
registry.register(obj2, "obj2-key");
obj2 = null; // obj2 eligible for GC โ€” callback will fire eventually

Common Tricky Questions

9. What is the output? (Explain why)

// Question 1
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}
// Output: 3, 3, 3
// Why: var is function-scoped, all closures share same i

// Fix with let
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}
// Output: 0, 1, 2 (let creates new binding each iteration)

// Question 2
console.log(typeof null); // "object" (historical bug!)
console.log(typeof undefined); // "undefined"
console.log(null == undefined); // true (loose equality)
console.log(null === undefined); // false (strict equality)

// Question 3
console.log(0.1 + 0.2 === 0.3); // false (floating point!)
console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON); // true

JavaScript interview success: understand the event loop deeply, know closure and scope, explain prototypal inheritance clearly, and demonstrate async mastery with promises and async/await. Modern ES features (optional chaining, nullish coalescing, WeakMap) show you keep up with the language. Always explain the “why” not just the syntax.

MD Rafikul Islam

Written by

MD Rafikul Islam is a software developer and the editor of TechPulse. He writes about developer tooling, hardware, and the practical decisions that come up in day-to-day engineering work โ€” which laptop to buy, which framework to commit to, why a build broke at 2am. He tests the tools he writes about and says plainly when something is not worth the money. Corrections and corrections requests are welcome at rony.yf25@gmail.com.

โœ๏ธ Leave a Comment

Your email address will not be published. Required fields are marked *