JavaScript interviews have shifted. Five years ago, you could get by explaining hoisting and the event loop. Today, interviewers expect you to understand modern patterns, performance tradeoffs, and real-world application architecture.
Here are the 50 questions that actually come up - organized from fundamentals to advanced. Each answer focuses on what interviewers are really evaluating.
Core Language (1-10)
1. What's the difference between let, const, and var?
var is function-scoped and hoisted. let and const are block-scoped and sit in the temporal dead zone until declared. const prevents reassignment but doesn't make objects immutable.
The real interview answer: "I use const by default, let when I need reassignment, and var never. Block scoping prevents an entire category of bugs."
2. Explain closures with a practical example.
A closure is a function that remembers variables from its outer scope even after that scope has finished executing.
function createCounter(initial = 0) {
let count = initial;
return {
increment: () => ++count,
decrement: () => --count,
getCount: () => count
};
}
const counter = createCounter(10);
counter.increment(); // 11
counter.increment(); // 12
counter.getCount(); // 12
Closures power module patterns, data privacy, partial application, and most callback patterns. If you understand closures, you understand half of JavaScript's design.
3. What is the event loop and how does it work?
JavaScript is single-threaded. The event loop manages concurrency by processing a call stack, a microtask queue (Promises, queueMicrotask), and a macrotask queue (setTimeout, setInterval, I/O).
Order of execution:
- Synchronous code on the call stack
- All microtasks (Promise callbacks,
queueMicrotask) - One macrotask
- All microtasks again
- Repeat
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// Output: 1, 4, 3, 2
4. What's the difference between == and ===?
== performs type coercion before comparison. === checks value and type without coercion.
0 == '' // true (both coerce to 0)
0 === '' // false (number vs string)
null == undefined // true
null === undefined // false
Always use ===. The coercion rules for == are a source of bugs that no one can memorize reliably.
5. How does this work in JavaScript?
this depends on how a function is called, not where it's defined:
- Regular function call:
thisisundefined(strict mode) orglobalThis - Method call:
thisis the object before the dot newkeyword:thisis the newly created objectcall/apply/bind:thisis explicitly set- Arrow function:
thisis inherited from the enclosing scope (lexicalthis)
const obj = {
name: 'Alice',
greet() { return this.name; }, // 'Alice'
greetArrow: () => this.name, // undefined (inherits outer this)
delayedGreet() {
setTimeout(() => console.log(this.name), 100); // 'Alice' (arrow inherits)
}
};
Arrow functions solving the this problem is one of the most important changes in modern JavaScript.
6. Explain prototypal inheritance.
Every JavaScript object has a prototype chain. When you access a property, the engine walks up the chain until it finds it or hits null.
const animal = { speak() { return `${this.name} makes a sound`; } };
const dog = Object.create(animal);
dog.name = 'Rex';
dog.speak(); // "Rex makes a sound"
Modern JavaScript uses class syntax, but it's syntactic sugar over prototypes. Understanding the chain helps you debug unexpected behavior and optimize performance.
7. What are the different ways to create objects?
// Object literal
const obj1 = { key: 'value' };
// Constructor
const obj2 = new Object();
// Object.create (prototype-based)
const obj3 = Object.create(proto);
// Class
class MyClass { constructor() { this.key = 'value'; } }
const obj4 = new MyClass();
// Factory function
const createObj = (key) => ({ key });
const obj5 = createObj('value');
In practice, object literals and classes cover 99% of use cases.
8. What is hoisting?
Hoisting moves declarations (not initializations) to the top of their scope during compilation.
console.log(x); // undefined (var is hoisted, value isn't)
var x = 5;
console.log(y); // ReferenceError (let is in temporal dead zone)
let y = 5;
hello(); // Works (function declarations are fully hoisted)
function hello() { return 'hi'; }
goodbye(); // TypeError (variable is hoisted, not the function)
var goodbye = function() { return 'bye'; };
9. What are generators and when would you use them?
Generators are functions that can pause and resume, yielding values on demand.
function* paginate(items, pageSize) {
for (let i = 0; i < items.length; i += pageSize) {
yield items.slice(i, i + pageSize);
}
}
const pager = paginate([1,2,3,4,5,6,7,8,9,10], 3);
pager.next(); // { value: [1,2,3], done: false }
pager.next(); // { value: [4,5,6], done: false }
Real uses: lazy evaluation, infinite sequences, custom iterables, and managing complex async flows with libraries like Redux-Saga.
10. Explain the difference between shallow copy and deep copy.
const original = { a: 1, nested: { b: 2 } };
// Shallow copy - nested objects are still shared
const shallow = { ...original };
shallow.nested.b = 99;
console.log(original.nested.b); // 99 (mutation leaked!)
// Deep copy - fully independent
const deep = structuredClone(original);
deep.nested.b = 99;
console.log(original.nested.b); // 2 (safe)
Use structuredClone() for deep copies. It handles circular references, Maps, Sets, and most built-in types. It's been available in all browsers and Node.js since 2022.
Functions & Scope (11-18)
11. What are arrow functions and how do they differ from regular functions?
Arrow functions are concise, but the differences go beyond syntax:
- No own
thisbinding (lexicalthis) - No
argumentsobject (use rest parameters) - Cannot be used as constructors (
newthrows) - No
prototypeproperty - Cannot be used as generator functions
Use arrow functions for callbacks and short expressions. Use regular functions for methods and constructors.
12. Explain call, apply, and bind.
All three set this explicitly:
function greet(greeting, punctuation) {
return `${greeting}, ${this.name}${punctuation}`;
}
const user = { name: 'Alice' };
greet.call(user, 'Hello', '!'); // "Hello, Alice!"
greet.apply(user, ['Hello', '!']); // "Hello, Alice!"
const bound = greet.bind(user, 'Hello');
bound('!'); // "Hello, Alice!"
call invokes immediately with individual args. apply invokes immediately with an array. bind returns a new function with this permanently set.
13. What is currying?
Currying transforms a function with multiple arguments into a sequence of functions each taking one argument.
const multiply = (a) => (b) => a * b;
const double = multiply(2);
const triple = multiply(3);
double(5); // 10
triple(5); // 15
Useful for creating specialized functions from general ones, middleware composition, and functional programming patterns.
14. What are pure functions and why do they matter?
A pure function always returns the same output for the same input and has no side effects.
// Pure
const add = (a, b) => a + b;
// Impure - depends on external state
let total = 0;
const addToTotal = (n) => total += n;
Pure functions are easier to test, debug, cache, and parallelize. React's rendering model is built on this principle.
15. Explain the module system (import/export).
// Named exports
export const API_URL = '/api';
export function fetchUser(id) { /* ... */ }
// Default export
export default class UserService { /* ... */ }
// Importing
import UserService, { API_URL, fetchUser } from './user-service.js';
// Dynamic import (code splitting)
const module = await import('./heavy-module.js');
ES modules are statically analyzed (enabling tree-shaking), loaded asynchronously, and have strict mode by default. CommonJS (require) is still used in Node.js but ESM is the standard going forward.
16. What is the temporal dead zone?
The TDZ is the period between entering a scope and the variable's declaration being processed. Accessing a let or const variable in its TDZ throws a ReferenceError.
{
// TDZ starts for x
console.log(x); // ReferenceError
let x = 5; // TDZ ends
}
This catches bugs that var would silently allow by returning undefined.
17. What are rest parameters and the spread operator?
Same syntax (...), different contexts:
// Rest - collects arguments into an array
function sum(...numbers) {
return numbers.reduce((a, b) => a + b, 0);
}
// Spread - expands an iterable into individual elements
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
// Object spread
const defaults = { theme: 'dark', lang: 'en' };
const settings = { ...defaults, lang: 'fr' }; // override lang
18. What is memoization?
Memoization caches function results based on arguments to avoid redundant computation.
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 expensiveFib = memoize(function fib(n) {
if (n <= 1) return n;
return expensiveFib(n - 1) + expensiveFib(n - 2);
});
React's useMemo and React.memo are built on this concept.
Async JavaScript (19-26)
19. What are Promises?
A Promise represents a value that may not exist yet. It's in one of three states: pending, fulfilled, or rejected.
function fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(response => {
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
})
.then(resolve)
.catch(reject);
});
}
Key methods: .then(), .catch(), .finally(), and the static methods Promise.all(), Promise.allSettled(), Promise.race(), Promise.any().
20. Explain async/await.
async/await is syntactic sugar over Promises that makes asynchronous code read like synchronous code.
async function getUserPosts(userId) {
try {
const user = await fetchUser(userId);
const posts = await fetchPosts(user.id);
return posts;
} catch (error) {
console.error('Failed to load posts:', error);
return [];
}
}
Common mistake: using await sequentially when operations are independent. Use Promise.all for parallel execution:
// Slow - sequential
const user = await fetchUser(id);
const posts = await fetchPosts(id);
// Fast - parallel
const [user, posts] = await Promise.all([
fetchUser(id),
fetchPosts(id)
]);
21. What's the difference between Promise.all, Promise.allSettled, Promise.race, and Promise.any?
const p1 = Promise.resolve(1);
const p2 = Promise.reject('error');
const p3 = Promise.resolve(3);
// all - rejects if ANY promise rejects
Promise.all([p1, p2, p3]); // Rejects with 'error'
// allSettled - waits for all, never rejects
Promise.allSettled([p1, p2, p3]); // [{status:'fulfilled', value:1},
// {status:'rejected', reason:'error'},
// {status:'fulfilled', value:3}]
// race - resolves/rejects with the first settled promise
Promise.race([p1, p2, p3]); // Resolves with 1
// any - resolves with first fulfilled, rejects only if ALL reject
Promise.any([p1, p2, p3]); // Resolves with 1
22. How do you handle errors in async code?
// try/catch with async/await
async function loadData() {
try {
const data = await fetchData();
return process(data);
} catch (error) {
if (error instanceof NetworkError) {
return getCachedData();
}
throw error; // Re-throw unexpected errors
}
}
// .catch() with Promises
fetchData()
.then(process)
.catch(handleError);
// Global handlers for uncaught errors
window.addEventListener('unhandledrejection', (event) => {
console.error('Unhandled promise rejection:', event.reason);
});
23. What is the fetch API and how has it evolved?
// Basic GET
const response = await fetch('/api/users');
const data = await response.json();
// POST with JSON
await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Alice' }),
signal: AbortSignal.timeout(5000) // timeout after 5s
});
Modern additions: AbortSignal.timeout(), request streaming, and the Response.json() static method.
24. What are Web Workers?
Web Workers run JavaScript in a background thread, keeping the main thread responsive.
// main.js
const worker = new Worker('worker.js');
worker.postMessage({ data: largeArray });
worker.onmessage = (event) => {
console.log('Result:', event.data);
};
// worker.js
self.onmessage = (event) => {
const result = heavyComputation(event.data);
self.postMessage(result);
};
Use cases: data processing, image manipulation, encryption, parsing large files. Workers can't access the DOM.
25. Explain the AbortController pattern.
AbortController lets you cancel async operations - most commonly fetch requests.
const controller = new AbortController();
// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);
try {
const response = await fetch('/api/data', {
signal: controller.signal
});
const data = await response.json();
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request was cancelled');
}
}
Essential for React cleanup in useEffect to prevent state updates on unmounted components.
26. What are async iterators?
Async iterators let you consume asynchronous data sources with for await...of.
async function* streamLines(url) {
const response = await fetch(url);
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop();
for (const line of lines) yield line;
}
if (buffer) yield buffer;
}
for await (const line of streamLines('/api/logs')) {
console.log(line);
}
Objects & Data Structures (27-33)
27. What are Map and Set?
// Map - key-value pairs with any key type
const map = new Map();
map.set({ id: 1 }, 'user object as key');
map.set(42, 'number as key');
map.size; // 2
// Set - unique values only
const set = new Set([1, 2, 2, 3, 3]);
[...set]; // [1, 2, 3]
// Real use: deduplication
const unique = [...new Set(arrayWithDuplicates)];
Use Map over plain objects when keys aren't strings or you need to track size. Use Set when you need uniqueness guarantees.
28. What are WeakMap and WeakSet?
Weak collections hold "weak" references that don't prevent garbage collection.
const cache = new WeakMap();
function getMetadata(element) {
if (cache.has(element)) return cache.get(element);
const metadata = computeMetadata(element);
cache.set(element, metadata);
return metadata;
}
// When element is garbage collected, cache entry is automatically removed
Key limitation: not iterable, no .size. Use them for caching and private data attached to objects.
29. Explain destructuring.
// Array destructuring
const [first, second, ...rest] = [1, 2, 3, 4, 5];
// first=1, second=2, rest=[3,4,5]
// Object destructuring with renaming and defaults
const { name: userName, age = 25, role = 'user' } = user;
// Nested destructuring
const { address: { city, zip } } = user;
// Function parameter destructuring
function createUser({ name, email, role = 'user' }) {
return { name, email, role };
}
30. What is optional chaining and nullish coalescing?
// Optional chaining (?.) - short-circuits to undefined
const city = user?.address?.city;
const first = arr?.[0];
const result = obj?.method?.();
// Nullish coalescing (??) - fallback only for null/undefined
const port = config.port ?? 3000;
// Compare with || which also catches 0, '', false
const count = data.count || 10; // 10 if count is 0 (probably wrong)
const count = data.count ?? 10; // 0 if count is 0 (probably right)
31. How does JSON.parse/JSON.stringify work and what are the gotchas?
// Basic serialization
const json = JSON.stringify({ name: 'Alice', age: 30 });
const obj = JSON.parse(json);
// Gotchas
JSON.stringify(undefined); // undefined (not a string)
JSON.stringify({ fn: () => {} }); // '{}' (functions stripped)
JSON.stringify({ date: new Date() }); // date becomes string
// Reviver for custom parsing
JSON.parse(json, (key, value) => {
if (key === 'date') return new Date(value);
return value;
});
// Replacer for custom serialization
JSON.stringify(obj, (key, value) => {
if (key === 'password') return undefined; // strip sensitive data
return value;
}, 2); // 2-space indentation
32. What are Symbols and when do you use them?
Symbols create unique identifiers that can't collide with other property keys.
const id = Symbol('id');
const user = { [id]: 123, name: 'Alice' };
user[id]; // 123
Object.keys(user); // ['name'] - symbols are hidden from enumeration
// Well-known symbols customize built-in behavior
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
[Symbol.iterator]() {
let current = this.start;
const end = this.end;
return {
next() {
return current <= end
? { value: current++, done: false }
: { done: true };
}
};
}
}
for (const n of new Range(1, 5)) console.log(n); // 1, 2, 3, 4, 5
33. What is the Proxy object?
Proxies intercept and customize fundamental operations on objects.
const validator = new Proxy({}, {
set(target, property, value) {
if (property === 'age' && typeof value !== 'number') {
throw new TypeError('Age must be a number');
}
if (property === 'age' && (value < 0 || value > 150)) {
throw new RangeError('Age must be between 0 and 150');
}
target[property] = value;
return true;
}
});
validator.age = 25; // Works
validator.age = 'old'; // TypeError
validator.age = -1; // RangeError
Used in Vue 3's reactivity system, validation libraries, and API clients.
DOM & Browser APIs (34-38)
34. What is event delegation?
Instead of attaching listeners to each child element, attach one to the parent and use the event's target to determine which child was clicked.
document.querySelector('.todo-list').addEventListener('click', (e) => {
const item = e.target.closest('.todo-item');
if (!item) return;
if (e.target.matches('.delete-btn')) {
item.remove();
} else if (e.target.matches('.toggle-btn')) {
item.classList.toggle('completed');
}
});
Benefits: fewer event listeners, automatically works for dynamically added elements, better memory usage.
35. What is the difference between localStorage, sessionStorage, and cookies?
| Feature | localStorage | sessionStorage | Cookies |
|---|---|---|---|
| Capacity | ~5-10MB | ~5-10MB | ~4KB |
| Expiry | Never | Tab close | Configurable |
| Sent to server | No | No | Every request |
| Scope | Origin | Origin + tab | Origin + path |
// localStorage
localStorage.setItem('theme', 'dark');
const theme = localStorage.getItem('theme');
// sessionStorage
sessionStorage.setItem('formDraft', JSON.stringify(formData));
Use localStorage for user preferences, sessionStorage for temporary form data, and cookies for server-side auth tokens.
36. What is the Intersection Observer API?
Efficiently detects when elements enter or leave the viewport.
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.src = entry.target.dataset.src; // lazy load
observer.unobserve(entry.target);
}
});
}, { threshold: 0.1 });
document.querySelectorAll('img[data-src]').forEach(img => {
observer.observe(img);
});
Use cases: lazy loading images, infinite scroll, analytics (tracking what users actually see), and triggering animations.
37. Explain event bubbling and capturing.
Events propagate in three phases: capture (top-down), target, and bubble (bottom-up).
// Bubbling (default) - inner fires first
parent.addEventListener('click', handler); // fires second
child.addEventListener('click', handler); // fires first
// Capturing - outer fires first
parent.addEventListener('click', handler, true); // fires first
child.addEventListener('click', handler, true); // fires second
// Stop propagation
child.addEventListener('click', (e) => {
e.stopPropagation(); // prevents event from reaching parent
});
38. What are service workers?
Service workers are proxy scripts between the browser and network, enabling offline functionality and push notifications.
// Register
navigator.serviceWorker.register('/sw.js');
// In sw.js - cache assets
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then(cache =>
cache.addAll(['/index.html', '/styles.css', '/app.js'])
)
);
});
// Serve from cache, fallback to network
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
Modern JavaScript & Patterns (39-50)
39. What are template literals and tagged templates?
// Template literals
const greeting = `Hello, ${name}! You have ${count} messages.`;
// Multi-line strings
const html = `
<div class="card">
<h2>${title}</h2>
<p>${description}</p>
</div>
`;
// Tagged templates - custom processing
function sql(strings, ...values) {
return {
text: strings.join('$'),
values: values
};
}
const query = sql`SELECT * FROM users WHERE id = ${userId} AND active = ${true}`;
// { text: 'SELECT * FROM users WHERE id = $ AND active = $', values: [userId, true] }
Tagged templates power libraries like styled-components and SQL query builders.
40. What are decorators?
Decorators (Stage 3, widely supported via TypeScript and Babel) add metadata or modify classes and methods.
function logged(originalMethod, context) {
return function(...args) {
console.log(`Calling ${context.name} with`, args);
const result = originalMethod.apply(this, args);
console.log(`${context.name} returned`, result);
return result;
};
}
class Calculator {
@logged
add(a, b) { return a + b; }
}
41. What is tree-shaking?
Tree-shaking removes unused code during bundling. It works because ES modules have static import/export declarations that can be analyzed at build time.
// math.js
export function add(a, b) { return a + b; }
export function multiply(a, b) { return a * b; }
// app.js
import { add } from './math.js';
// multiply is tree-shaken out of the final bundle
For tree-shaking to work: use ES modules (not CommonJS), avoid side effects in modules, and mark packages as side-effect-free in package.json.
42. What design patterns do you use in JavaScript?
Observer pattern:
class EventEmitter {
#listeners = new Map();
on(event, callback) {
if (!this.#listeners.has(event)) this.#listeners.set(event, []);
this.#listeners.get(event).push(callback);
}
emit(event, ...args) {
this.#listeners.get(event)?.forEach(cb => cb(...args));
}
}
Module pattern (encapsulation via closures or ES modules), Factory pattern (creating objects without new), and Strategy pattern (swappable algorithms) are the most common in modern JS.
43. What are private class fields?
class BankAccount {
#balance = 0; // truly private
deposit(amount) {
if (amount <= 0) throw new Error('Invalid amount');
this.#balance += amount;
}
get balance() { return this.#balance; }
}
const account = new BankAccount();
account.deposit(100);
account.balance; // 100
account.#balance; // SyntaxError - truly private
Unlike the _underscore convention, # fields are enforced by the engine. They can't be accessed outside the class.
44. What is the structuredClone API?
structuredClone() creates deep copies of values, handling cases that JSON.parse(JSON.stringify()) can't:
const original = {
date: new Date(),
regex: /test/gi,
set: new Set([1, 2, 3]),
nested: { deep: { value: 42 } }
};
const clone = structuredClone(original);
clone.date instanceof Date; // true (JSON would make it a string)
clone.set instanceof Set; // true (JSON would lose it entirely)
Limitations: can't clone functions, DOM nodes, or objects with prototype chains.
45. How does error handling work with Error types?
// Custom error types
class ValidationError extends Error {
constructor(field, message) {
super(message);
this.name = 'ValidationError';
this.field = field;
}
}
// Error cause chaining (ES2022)
try {
await fetchUserData();
} catch (error) {
throw new Error('Failed to load user profile', { cause: error });
}
// Catching specific types
try {
validateInput(data);
} catch (error) {
if (error instanceof ValidationError) {
showFieldError(error.field, error.message);
} else {
throw error; // re-throw unexpected errors
}
}
46. What are Records and Tuples?
Records and Tuples (Stage 2 proposal) are deeply immutable data structures that compare by value:
// Not yet in engines - available via polyfill/babel
const record = #{ name: 'Alice', age: 30 };
const tuple = #[1, 2, 3];
#{ a: 1 } === #{ a: 1 } // true (value equality!)
#[1, 2] === #[1, 2] // true
Until they ship, use Object.freeze() for shallow immutability or libraries like Immer for immutable update patterns.
47. What is the Iterator protocol?
Any object with a [Symbol.iterator]() method that returns { next() } is iterable:
class Fibonacci {
[Symbol.iterator]() {
let [a, b] = [0, 1];
return {
next() {
[a, b] = [b, a + b];
return { value: a, done: false };
}
};
}
}
// Take first 10 Fibonacci numbers
const fibs = [];
for (const n of new Fibonacci()) {
if (fibs.length >= 10) break;
fibs.push(n);
}
48. How do you handle memory leaks in JavaScript?
Common sources and fixes:
// 1. Event listeners not cleaned up
const handler = () => { /* ... */ };
element.addEventListener('click', handler);
// Fix: element.removeEventListener('click', handler);
// 2. Closures holding references
function createHandler(heavyData) {
return () => console.log(heavyData); // heavyData never freed
}
// Fix: null out references when done
// 3. Forgotten timers
const id = setInterval(() => updateDashboard(), 1000);
// Fix: clearInterval(id) when component unmounts
// 4. Detached DOM nodes
const nodes = [];
nodes.push(document.createElement('div')); // reference keeps node alive
Use Chrome DevTools Memory tab to identify leaks: take heap snapshots, compare, and look for growing retained sizes.
49. What's new in recent ECMAScript versions?
ES2024:
Object.groupBy()andMap.groupBy()Promise.withResolvers()- Well-formed Unicode strings
ES2025:
Setmethods:union(),intersection(),difference(),symmetricDifference()Iterator.prototypemethods:.map(),.filter(),.take(),.drop()RegExpescaping
// Object.groupBy
const people = [{ name: 'Alice', dept: 'eng' }, { name: 'Bob', dept: 'eng' }];
Object.groupBy(people, p => p.dept);
// { eng: [{ name: 'Alice', dept: 'eng' }, { name: 'Bob', dept: 'eng' }] }
// Set methods
new Set([1,2,3]).union(new Set([3,4,5])); // Set {1,2,3,4,5}
50. How do you optimize JavaScript performance?
Rendering:
- Use
requestAnimationFramefor visual updates - Batch DOM reads/writes to avoid layout thrashing
- Use CSS
containandcontent-visibilityfor rendering optimization
JavaScript:
- Debounce/throttle expensive event handlers
- Use Web Workers for CPU-intensive tasks
- Lazy load modules with dynamic
import() - Use
Map/Setfor frequent lookups instead of arrays
Network:
- Preload critical resources with
<link rel="preload"> - Use
loading="lazy"on images - Implement request deduplication and caching
Measurement:
// Performance API
performance.mark('start');
doExpensiveWork();
performance.mark('end');
performance.measure('work', 'start', 'end');
console.log(performance.getEntriesByName('work')[0].duration);
How to Use This List
Don't memorize answers. Understand the concepts well enough to explain them in your own words and apply them to real problems.
For each topic, ask yourself:
- Can I explain this to someone who hasn't seen it before?
- Can I write a working example without looking anything up?
- Do I know when I'd use this in a real project?
If you can do all three, you're ready.
Practice JavaScript interview questions with real-time feedback at gitGood.dev. Build the skills that actually get you hired.