12 Frontend Interview Questions That Senior Devs Still Get Wrong
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
setTimeoutcreates a macrotask (task queue).Promise.thencreates 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
| Selector | IDs | Classes | Elements |
|---|---|---|---|
#header .nav li a | 1 | 1 | 2 |
.nav-link.active | 0 | 2 | 0 |
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, 42️⃣ 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, 4Why 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/constare 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+)
| Metric | Meaning | Status |
|---|---|---|
| LCP – Largest Contentful Paint | Loading performance | ✅ |
| CLS – Cumulative Layout Shift | Visual stability | ✅ |
| INP – Interaction to Next Paint | Responsiveness (replaces FID) | ✅ |
| FID – First Input Delay | Deprecated (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
widthandheight(or usingaspect-ratio):<img src="photo.jpg" width="800" height="600" alt="...">INP – Break up long tasks with
scheduler.yield()orrequestIdleCallback:// 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'));| Combinator | When to use |
|---|---|
Promise.all | All‑or‑nothing operations (e.g., loading initial app data). |
Promise.allSettled | Partial success is acceptable (e.g., dashboard widgets). |
Promise.race | First response wins (e.g., fastest CDN). |
Promise.any | First 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 → CompositeKey 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
- HTML arrives → browser shows content (fast FCP).
- JS downloads → framework “hydrates”.
- 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 KBWhy tree‑shaking fails
- CommonJS (
require) can’t be statically analyzed. - Side‑effects in modules prevent elimination.
- Missing
"sideEffects": falseinpackage.json. - Barrel files (
index.jsre‑exports) defeat static analysis.
Check your bundle
npx webpack-bundle-analyzer12️⃣ 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
thisbinding 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 Sheet | Price |
|---|---|
| 📊 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.