12 Frontend Interview Questions That Senior Devs Still Get Wrong

Published: (February 23, 2026 at 05:17 AM EST)
8 min read
Source: Dev.to

Source: Dev.to

Source: Dev.to – 12 Frontend Interview Questions That Senior Devs Still Get Wrong

1️⃣ Event‑Loop Execution Order

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

Answer: 1, 4, 3, 2

Why seniors get it wrong

  • setTimeout creates a macrotask (task queue).
  • Promise.then creates a microtask.
  • The event loop empties the microtask queue before moving on to the next macrotask.

Interview tip
Draw the call stack, the micro‑task queue, and the macro‑task queue. Visual thinking is a big plus for interviewers.

2️⃣ CSS Specificity

#header .nav li a { color: blue; }   /* Specificity: 0‑1‑2‑1 */
.nav-link.active { color: red; }     /* Specificity: 0‑0‑2‑0 */

Answer: Blue wins.

The trap: Many senior developers think “more classes = higher specificity.” An ID selector (#header) outranks any number of class selectors.

Specificity Table

SelectorIDsClassesElements
#header .nav li a112
.nav-link.active020

Specificity is a tuple, not a single number.

3️⃣ var vs. let in Loops

function createButtons() {
  const buttons = [];

  // ❌ Using `var` – the loop variable is function‑scoped
  for (var i = 0; i < 5; i++) {
    // each iteration pushes a function that logs `i`
    buttons.push(() => console.log(i));
  }

  return buttons;
}

createButtons().forEach(btn => btn());
// Output: 5, 5, 5, 5, 5  (not 0, 1, 2, 3, 4)

Why it happens

var is function‑scoped, so the single i variable lives for the whole lifetime of createButtons.
When the callbacks run later, they all read the final value of i (which is 5 after the loop ends).


✅ Fixes

1️⃣ Block‑scoped let

function createButtons() {
  const buttons = [];

  // `let` creates a fresh binding for each iteration
  for (let i = 0; i < 5; i++) {
    buttons.push(() => console.log(i));
  }

  return buttons;
}

createButtons().forEach(btn => btn());
// Output: 0, 1, 2, 3, 4

2️⃣ IIFE (Immediately‑Invoked Function Expression) – classic var solution

function createButtons() {
  const buttons = [];

  for (var i = 0; i < 5; i++) {
    (function (j) {
      // `j` is a copy of the current value of `i`
      buttons.push(() => console.log(j));
    })(i);
  }

  return buttons;
}

createButtons().forEach(btn => btn());
// Output: 0, 1, 2, 3, 4

Why it matters

Understanding the difference between function scope (var) and block scope (let/const) is essential for:

  • Avoiding unexpected closure bugs like the one above.
  • Writing memory‑efficient code (no unnecessary references to a single mutable variable).
  • Debugging and maintaining modern JavaScript codebases where let/const are the norm.

4️⃣ this in Arrow Functions

const obj = {
  name: 'Widget',
  getName: () => this.name,
  getNameFn() { return this.name; }
};

console.log(obj.getName());   // undefined
console.log(obj.getNameFn()); // 'Widget'

Explanation
Arrow functions don’t have their own this; they inherit it from the lexical environment (the module/global scope in this example). Regular functions get this bound to the calling object.

Senior trap

“I always use arrow functions.” – Do you know when not to?

5️⃣ Virtual DOM (VDOM) Myth

Common belief: “VDOM makes React fast.”

Reality:

  • VDOM adds diffing overhead.
  • Direct DOM manipulation is faster for simple, targeted updates.
  • VDOM shines when you don’t know what changed (declarative UI).
  • Frameworks like Svelte prove you can achieve great performance without a VDOM.

Interview answer:

“VDOM is a trade‑off: it gives us declarative UI at the cost of diffing overhead. It’s not inherently fast; it’s fast enough while being developer‑friendly.”

6️⃣ Core Web Vitals (2024+)

MetricMeaningStatus
LCP – Largest Contentful PaintLoading performance
CLS – Cumulative Layout ShiftVisual stability
INP – Interaction to Next PaintResponsiveness (replaces FID)
FID – First Input DelayDeprecated (replaced by INP in March 2024)

Senior trap: Knowing the acronyms but not how to improve them.

Quick Wins

  • LCP – Preload the hero image and set fetchpriority="high":

    <link rel="preload" href="/hero.jpg" as="image" fetchpriority="high">
  • CLS – Reserve space for media by specifying explicit width and height (or using aspect-ratio):

    <img src="photo.jpg" width="800" height="600" alt="...">
  • INP – Break up long tasks with scheduler.yield() or requestIdleCallback:

    // Example using scheduler.yield()
    import { yield as schedulerYield } from 'scheduler';
    
    async function heavyTask() {
      for (let i = 0; i < 1000; i++) {
        // do a chunk of work
        await schedulerYield(); // yields to the main thread
      }
    }

These small changes can dramatically improve your Core Web Vitals scores with minimal effort.

7️⃣ Promise Combinators

// Promise.all – fails fast
Promise.all([fetch('/a'), fetch('/b'), fetch('/c')])
  .catch(err => /* ONE failure kills ALL */);

// Promise.allSettled – always completes
Promise.allSettled([fetch('/a'), fetch('/b'), fetch('/c')])
  .then(results => results.filter(r => r.status === 'fulfilled'));
CombinatorWhen to use
Promise.allAll‑or‑nothing operations (e.g., loading initial app data).
Promise.allSettledPartial success is acceptable (e.g., dashboard widgets).
Promise.raceFirst response wins (e.g., fastest CDN).
Promise.anyFirst successful response wins (e.g., fallback APIs).

8️⃣ Media Queries vs. Container Queries

/* Viewport‑based */
@media (min-width: 768px) {
  .card { flex-direction: row; }
}

/* Container‑based */
@container (min-width: 400px) {
  .card { flex-direction: row; }
}

Why it matters:
Components should adapt to their container, not just the viewport. A card inside a sidebar should stay narrow even on a wide screen.

Senior trap:
Still relying only on media queries in 2026. Container queries now have 95 %+ browser support.

9️⃣ Map vs. WeakMap (Memory Leaks)

// Regular Map – can cause leaks
const cache = new Map();

function process(obj) {
  cache.set(obj, expensiveComputation(obj));
  // `obj` can never be garbage‑collected while it remains in the Map
}

// WeakMap – no leak
const cache = new WeakMap();

function process(obj) {
  cache.set(obj, expensiveComputation(obj));
  // `obj` can be GC'd when there are no other references
}

Typical use cases

  • Storing metadata for DOM elements.
  • Implementing private class fields.
  • Caching values without preventing garbage collection.

🔟 From URL to Pixels (Browser Rendering Pipeline)

DNS → TCP → TLS → HTTP → HTML parsing → CSSOM → Render Tree
      → Layout → Paint → Composite

Key insights

  • CSS blocks rendering.
  • JavaScript blocks HTML parsing (unless defer/async).

Performance pattern

<!-- Example: a minimal page that delays rendering -->
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Demo</title>
  <link rel="stylesheet" href="styles.css">   <!-- CSS blocks paint -->
  <script src="bundle.js" defer></script>    <!-- defer → non‑blocking -->
</head>
<body>
  <h1>Hello, world!</h1>
</body>
</html>

SSR flow

  1. HTML arrives → browser shows content (fast FCP).
  2. JS downloads → framework “hydrates”.
  3. Page becomes interactive (TTI).

Hydration tax – the gap between FCP and TTI.

Modern solutions

  • Partial hydration – e.g., Astro islands.
  • Resumability – Qwik (zero hydration).
  • Streaming SSR – React 18 Suspense.
  • Progressive hydration – load JS only for visible components first.

Senior answer: “I’d first evaluate whether we even need client‑side JS for this component.”

1️⃣ Tree‑Shaking & Bundle Size

// ❌ Imports EVERYTHING
import _ from 'lodash';               // ~71 KB gzipped

// ✅ Imports only what you need
import debounce from 'lodash-es/debounce'; // ~1 KB

Why tree‑shaking fails

  • CommonJS (require) can’t be statically analyzed.
  • Side‑effects in modules prevent elimination.
  • Missing "sideEffects": false in package.json.
  • Barrel files (index.js re‑exports) defeat static analysis.

Check your bundle

npx webpack-bundle-analyzer

12️⃣ Real‑World Interview Question Checklist

These 12 questions are taken from 40+ actual frontend interviews (2022‑2026). They separate senior from truly senior developers.

  • Understand the event loop (micro‑ vs. macro‑tasks).
  • Master CSS specificity calculations.
  • Know the difference between var, let, and IIFE closures.
  • Be aware of this binding rules for arrow vs. regular functions.
  • Have a nuanced view of the Virtual DOM trade‑offs.
  • Keep up‑to‑date with Core Web Vitals (especially INP).
  • Choose the right Promise combinator for the problem.
  • Use container queries where appropriate.
  • Prevent memory leaks with WeakMap.
  • Explain the browser rendering pipeline and hydration costs.
  • Optimize bundles with proper tree‑shaking techniques.

Good luck! 🎉

Cheat Sheet Overview

Cheat Sheet — covering React internals, TypeScript advanced patterns, system design for front‑ends, and accessibility gotchas.

More Cheat Sheets

Cheat SheetPrice
📊 50 DSA Patterns for Coding Interviews$9
🏗️ 40 System Design Patterns$9
🗃️ SQL Interview Patterns$7

Building Something?

Check out DonFlow — a budget‑drift detector that runs entirely in your browser.
Zero backend, zero signup, and your data never leaves your device.

0 views
Back to Blog

Related posts

Read more »