Skills & Technologies

JavaScript Interview Questions & Answers for All Levels

19 min readUpdated April 20, 2025
JavaScriptclosuresevent loop
JavaScript remains the most widely used programming language in the world, powering everything from interactive websites and single-page applications to server-side APIs and mobile apps. As a result, JavaScript interview questions appear across frontend, full-stack, and even backend engineering roles. This guide covers the essential JavaScript concepts that interviewers test most frequently: from foundational topics like closures, prototypes, and the event loop to modern ES6+ features and async patterns. Whether you are preparing for your first developer role or targeting a senior position, these questions and answers will help you demonstrate deep language mastery.

Core JavaScript Concepts

These questions test your understanding of JavaScript's fundamental mechanics. Strong candidates demonstrate mastery of: • Scope and closures — how lexical scoping works and why closures are powerful • Prototypal inheritance — the prototype chain, Object.create(), and how class syntax maps to prototypes • The event loop — call stack, task queue, microtask queue, and how asynchronous code executes • Type coercion — implicit vs explicit conversion, == vs ===, and truthy/falsy values

Q1.What are closures in JavaScript? Provide a practical example of when you would use one.

intermediate
A closure is a function that retains access to its outer (enclosing) scope's variables even after the outer function has returned. Every function in JavaScript forms a closure over the scope in which it was created. How closures work: • When a function is defined, it captures a reference to its lexical environment • This environment persists as long as the closure exists, even if the outer function has finished executing • The closure has access to three scope chains: its own scope, the outer function's variables, and global variables Practical example — data privacy: function createCounter() { let count = 0; return { increment: () => ++count, getCount: () => count }; } Here, count is private — it cannot be accessed directly from outside, only through the returned methods. Common use cases: • Module patterns for data encapsulation • Function factories and partial application • Event handlers that need to remember state • Memoization and caching

Q2.Explain the JavaScript event loop. How do microtasks and macrotasks differ?

advanced
The event loop is the mechanism that allows JavaScript to perform non-blocking operations despite being single-threaded. It continuously checks whether the call stack is empty and, if so, processes pending tasks. Execution order: 1. Execute all synchronous code on the call stack 2. When the call stack is empty, process ALL microtasks in the microtask queue 3. Process ONE macrotask from the macrotask queue 4. Repeat from step 2 Microtasks (higher priority): • Promise.then() / .catch() / .finally() • queueMicrotask() • MutationObserver Macrotasks (lower priority): • setTimeout() / setInterval() • setImmediate() (Node.js) • I/O operations • UI rendering events Key insight: Microtasks are fully drained before the next macrotask runs. This means a Promise.resolve().then() will always execute before a setTimeout(cb, 0), even though both are asynchronous. Common interview trap: console.log('1'); setTimeout(() => console.log('2'), 0); Promise.resolve().then(() => console.log('3')); console.log('4'); Output: 1, 4, 3, 2

Q3.What is prototypal inheritance in JavaScript? How does it differ from classical inheritance?

intermediate
JavaScript uses prototypal inheritance: objects inherit directly from other objects via the prototype chain. There are no classes at the engine level — the class keyword is syntactic sugar over prototypes. How the prototype chain works: • Every object has an internal [[Prototype]] link (accessible via Object.getPrototypeOf() or __proto__) • When you access a property on an object, JavaScript walks up the prototype chain until it finds the property or reaches null • Methods defined on Constructor.prototype are shared across all instances (memory efficient) Key differences from classical inheritance: • No classes at the engine level — objects delegate to other objects • Any object can be a prototype, not just class definitions • Prototypes are live — adding a method to a prototype instantly makes it available to all instances Creating inheritance: • Object.create(proto) — creates a new object with proto as its prototype • Constructor functions with new — sets prototype automatically • ES6 class / extends — cleaner syntax, same mechanism underneath Best practice: Favor composition over deep inheritance chains. Use mixins or object composition for code reuse.

ES6+ Features & Modern JavaScript

Modern JavaScript (ES6 and beyond) introduced features that fundamentally changed how developers write code. Interviewers expect fluency with: • Variable declarations — let, const, and the death of var • Arrow functions — lexical this binding and concise syntax • Destructuring and spread — extracting values and merging objects/arrays • Modules — import/export, tree-shaking, and dynamic imports • Iterators and generators — Symbol.iterator, function*, and yield

Q4.What are the differences between var, let, and const? When should you use each?

beginner
Scoping: • var — function-scoped (or global if declared outside a function) • let and const — block-scoped (scoped to the nearest {} block) Hoisting behavior: • var — hoisted and initialized to undefined (can be used before declaration without error, but value is undefined) • let / const — hoisted but NOT initialized (accessing before declaration throws ReferenceError — the Temporal Dead Zone) Reassignment: • var and let — can be reassigned • const — cannot be reassigned, but the value itself can be mutated if it's an object or array Best practices: 1. Use const by default — signals that the binding won't change 2. Use let only when you need to reassign (loop counters, accumulated values) 3. Never use var in modern code — block scoping prevents entire categories of bugs Common gotcha: for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); } // Logs: 3, 3, 3 (var is function-scoped) for (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); } // Logs: 0, 1, 2 (let creates new binding per iteration)

Async JavaScript Patterns

Asynchronous programming is central to JavaScript. Interviewers test your understanding of: • Callbacks — the original async pattern, callback hell, and error-first convention • Promises — .then() chaining, Promise.all(), Promise.race(), Promise.allSettled() • Async/await — syntactic sugar over Promises, error handling with try/catch • Concurrent patterns — parallelizing independent operations, controlling concurrency

Q5.Compare Promises with async/await. What are the advantages of each?

intermediate
Both Promises and async/await handle asynchronous operations, but they offer different ergonomics. Promises: • Provide explicit chaining with .then() and .catch() • Better for composing multiple async operations with combinators: Promise.all(), Promise.race(), Promise.allSettled() • Can become hard to read with complex chains (though better than callbacks) Async/await: • Makes asynchronous code look synchronous — easier to read and reason about • Error handling uses standard try/catch blocks instead of .catch() • Easier to debug — stack traces are cleaner, and you can step through with a debugger When to use which: • Use async/await for sequential async operations and when readability matters most • Use Promise.all() when you need to run independent async operations in parallel • Combine both: await Promise.all([fetch(url1), fetch(url2)]) Common mistake to avoid: • Unnecessary sequential awaits: // Bad — sequential (slow) const a = await fetchA(); const b = await fetchB(); // Good — parallel (fast) const [a, b] = await Promise.all([fetchA(), fetchB()]);

Q6.What is the difference between Promise.all(), Promise.allSettled(), and Promise.race()?

advanced
These are Promise combinators for handling multiple concurrent promises. Promise.all(promises): • Resolves when ALL promises resolve, with an array of results • Rejects immediately if ANY promise rejects (fail-fast) • Use when: all operations must succeed (e.g., fetching data from multiple required APIs) Promise.allSettled(promises): • Waits for ALL promises to settle (resolve or reject) • Never rejects — returns an array of {status, value/reason} objects • Use when: you need results from all operations regardless of individual failures (e.g., batch processing where partial success is acceptable) Promise.race(promises): • Resolves or rejects as soon as the FIRST promise settles • Use when: you want the fastest response (e.g., querying multiple redundant servers) or implementing timeouts Promise.any(promises) (ES2021): • Resolves when the FIRST promise resolves (ignores rejections) • Rejects only if ALL promises reject (with an AggregateError) • Use when: you want the first successful result from multiple attempts

Frequently Asked Questions

Should I learn TypeScript or JavaScript for interviews?+

Know JavaScript deeply first — TypeScript is a superset, and most interview questions test core JavaScript concepts. However, if the role involves TypeScript, demonstrating type system knowledge (generics, utility types, discriminated unions) is a strong positive. Many companies let you choose either during coding rounds.

How important are JavaScript frameworks for interviews?+

Framework-specific questions (React, Vue, Angular) are typically separate from core JavaScript rounds. However, understanding the underlying JavaScript concepts — closures, the event loop, prototypes, async patterns — is essential regardless of framework. A strong JavaScript foundation makes framework questions much easier.

What level of ES6+ knowledge is expected in 2025?+

ES6+ features are no longer 'new' — they are the standard. Interviewers expect fluent use of arrow functions, destructuring, template literals, modules, Promises, async/await, optional chaining, and nullish coalescing. Newer features like Array.at(), structuredClone(), and top-level await are bonus points.

Ready to land your dream job?

CareerUplift gives you AI-powered mock interviews, an ATS-optimized resume builder, and personalized coaching — everything you need to get hired faster.

Related Articles