Sitemap

Top 20 JavaScript Interview Questions Explained Simply

7 min readSep 15, 2026

--

Press enter or click to view image in full size

Hey devs! 👋

Let’s be honest: JavaScript interviews can feel a bit like a game of trivia show roulette. One minute you’re building sleek frontend components, and the next, an interviewer asks you to explain the event loop using a whiteboard while you sweat through your t-shirt. 😅

To save you from that pre-interview panic, I’ve put together 20 of the most frequently asked JavaScript interview questions, explained in plain, conversational English — no overly dry textbook definitions required.

Grab your beverage of choice, and let’s dive in! ☕👇

1. What’s the difference between var, let, and const?

Think of var as the old-school way we used to declare variables. It’s function-scoped and gets hoisted (meaning JS moves the declaration to the top). The problem? It lets you re-declare variables in the same scope, leading to weird bugs.

let and const were introduced in ES6 to save our sanity:

  • let is block-scoped (lives inside {}) and allows re-assignment.
  • const is also block-scoped, but once assigned, you can’t re-assign it. (Pro-tip: Object properties inside a const can still be updated!)
var x = 10;
var x = 20; // Allowed! (Can cause bugs)
let y = 10;
// let y = 20; // Error: Identifier 'y' has already been declared
const z = 10;
// z = 20; // Error: Assignment to constant variable.

2. How does Hoisting actually work?

JavaScript reads your code twice before running it. In the first pass, it takes variable and function declarations and conceptually moves them to the top of their scope.

  • Functions are fully hoisted, so you can call them before they appear in the file.
  • var is hoisted with a default value of undefined.
  • let and const are hoisted too, but kept in a "Temporal Dead Zone" (TDZ) until the engine hits their line of code. Trying to touch them early throws a ReferenceError.
console.log(a); // undefined
var a = 5;
// console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 10;

3. What’s the difference between == and ===?

  • == (Loose Equality): Checks value after attempting type coercion. So, '5' == 5 returns true.
  • === (Strict Equality): Checks both value AND type without converting anything. So, '5' === 5 returns false.

Rule of thumb: Stick to === almost everywhere to avoid unexpected JavaScript magic.

4. Can you explain Closures like I’m 5?

A closure happens when an inner function remembers variables from its outer (parent) function, even after that parent function has finished executing.

function makeCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2

counter keeps access to count because of closures!

5. What is the Event Loop?

JavaScript is single-threaded — it can only do one thing at a time. So how does it handle fetch requests and timers without freezing the screen?

  1. Call Stack: Executes synchronous code line by line.
  2. Web APIs: Browser handles timers, fetch requests, DOM events in the background.
  3. Callback Queue: Holds callback functions ready to run.
  4. Event Loop: Continuously checks if the Call Stack is empty. When it is, it takes the first task from the queue and pushes it onto the stack.

6. Microtasks vs. Macrotasks: What runs first?

When asynchronous code completes, it goes into one of two queues:

  • Microtask Queue: Promises (.then(), .catch()), queueMicrotask, async/await.
  • Macrotask Queue: setTimeout, setInterval, I/O events.

Microtasks always take priority. The event loop clears out all microtasks before moving to the next macrotask.

console.log('1');
setTimeout(() => console.log('2'), 0); // Macrotask
Promise.resolve().then(() => console.log('3')); // Microtask
console.log('4');
// Output order: 1, 4, 3, 2

7. What does the this keyword refer to?

this refers to the context in which a function is called:

  1. Global scope: this points to window (or undefined in strict mode).
  2. Method on an object: this points to the object calling the method (obj.greet()).
  3. Event Listener: this points to the HTML element that received the event.
  4. Arrow Functions: They don’t have their own this; they inherit it lexically from the surrounding scope.

8. What are call, apply, and bind?

All three let you manually set the value of this:

  • call(thisArg, arg1, arg2): Invokes the function immediately; arguments passed individually.
  • apply(thisArg, [arg1, arg2]): Invokes the function immediately; arguments passed as an array.
  • bind(thisArg, arg1, arg2): Doesn’t run immediately; returns a new function bound to thisArg.
function greet(greeting, punctuation) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
const user = { name: 'Alex' };greet.call(user, 'Hello', '!'); // "Hello, Alex!"
greet.apply(user, ['Hi', '.']); // "Hi, Alex."
const boundGreet = greet.bind(user, 'Hey');
boundGreet('?'); // "Hey, Alex?"

9. What is Prototype / Prototypal Inheritance?

In JS, objects inherit properties and methods from other objects through a chain known as the prototype chain.

Get Dev Raj Sharma’s stories in your inbox

Join Medium for free to get updates from this writer.

When you look up arr.push(), JS checks if push is directly on arr. If not, it looks up Array.prototype. If not found there, it goes up to Object.prototype, until it hits null.

const animal = { eats: true };
const dog = Object.create(animal);
dog.barks = true;
console.log(dog.barks); // true
console.log(dog.eats); // true (inherited via prototype)

10. What are Promises and why do we use them?

A Promise represents a value that will be available now, later, or never. It solves “Callback Hell” (nesting callbacks deep inside each other).

A Promise has 3 states:

  1. Pending (Waiting)
  2. Fulfilled (Success — .then())
  3. Rejected (Error — .catch())
const fetchData = new Promise((resolve, reject) => {
let success = true;
if (success) resolve("Data loaded");
else reject("Server error");
});
fetchData
.then(res => console.log(res))
.catch(err => console.error(err));

11. How does async/await work behind the scenes?

async/await is syntactic sugar built on top of Promises!

  • Marking a function as async makes it automatically return a Promise.
  • await pauses execution inside the async function until the Promise resolves or rejects, making asynchronous code look like clean, linear code.
async function getUser() {
try {
const res = await fetch('https://api.example.com/user');
const data = await res.json();
console.log(data);
} catch (error) {
console.error('Fetch failed:', error);
}
}

12. What’s the difference between Deep Copy and Shallow Copy?

  • Shallow Copy: Copies top-level properties. Nested objects still reference the original memory location (Object.assign(), Spread { ...obj }).
  • Deep Copy: Recursively copies everything, creating a completely independent object (structuredClone(obj) or JSON.parse(JSON.stringify(obj))).
const original = { a: 1, nested: { b: 2 } };
// Shallow Copy
const shallow = { ...original };
shallow.nested.b = 99;
console.log(original.nested.b); // 99 (mutated original!)
// Deep Copy
const deep = structuredClone(original);
deep.nested.b = 500;
console.log(original.nested.b); // 99 (original is safe!)

13. What is Debouncing and Throttling?

Both optimize high-frequency events like window scrolling or typing:

  • Debouncing: Delays execution until a specified delay passes after the last trigger (e.g., waiting until a user finishes typing in a search bar).
  • Throttling: Limits execution to at most once every $X$ milliseconds (e.g., handling window resize events smoothly).

14. What are Higher-Order Functions (HOFs)?

A Higher-Order Function is a function that either:

  1. Takes one or more functions as arguments (e.g., map, filter, reduce), OR
  2. Returns another function.
const double = num => num * 2;
const numbers = [1, 2, 3];
// map is a HOF because it takes the function 'double' as an argument
const doubled = numbers.map(double); // [2, 4, 6]

15. Map vs. Set vs. Object: When to use which?

  • Object: Key-value store (keys are strings/symbols). Great for fixed data structures.
  • Map: Key-value store where keys can be any data type (objects, numbers, functions). Preserves insertion order and has better performance for frequent additions/deletions.
  • Set: A collection of unique values of any type. Perfect for removing duplicates from arrays ([...new Set(array)]).

16. What is Event Bubbling and Event Capturing?

When an event happens on an element inside another element (like a button inside a <div>):

  • Capturing Phase: The event travels from top DOM node down to the target element.
  • Bubbling Phase (Default): The event triggers on the target element and travels up through parent containers.

(You can stop propagation anytime using e.stopPropagation())

17. What is Event Delegation?

Instead of adding event listeners to multiple child elements (e.g., 50 list items), you add a single listener to their parent container. You then use e.target to identify which child was clicked.

It saves memory and works automatically for newly added DOM nodes!

document.getElementById('parent-list').addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
console.log('Clicked item:', e.target.textContent);
}
});

18. What is the difference between Object.freeze() and Object.seal()?

  • Object.freeze(): Completely locks down an object. You can’t add, remove, or modify properties.
  • Object.seal(): Prevents adding or removing properties, but you can still update existing property values.

19. What are Rest and Spread operators?

They share the same syntax (...), but serve opposite purposes:

  • Spread: Expands elements of an array/object into individual items (const clone = [...arr]).
  • Rest: Collects multiple remaining elements into an array (function sum(...numbers)).
// Spread
const nums = [1, 2, 3];
const newNums = [...nums, 4, 5]; // [1, 2, 3, 4, 5]
// Rest
function sum(...args) {
return args.reduce((acc, current) => acc + current, 0);
}

20. What is a Pure Function?

A Pure Function satisfies two strict conditions:

  1. Given the same inputs, it always returns the exact same output.
  2. It produces no side effects (doesn’t mutate external state, modify global variables, or perform network calls).
// Pure (Always returns same output for same inputs, no side effects)
const add = (a, b) => a + b;
// Impure (Relies on outside state)
let tax = 0.1;
const calculateTotal = (price) => price + (price * tax);

Wrapping Up 🎁

Mastering these 20 concepts won’t just help you pass your next interview — it’ll genuinely make you a cleaner, more confident developer day-to-day.

Got a favorite JavaScript interview question that tripped you up recently? Drop it in the comments below! 👇

Happy coding! 💻✨

--

--