JavaScript interviews concentrate on a handful of areas that behave differently from every other language a candidate has used: scope, the event loop, this, and prototypes. These are the questions that come up, answered the way you would explain them out loud.
Scope, closures and hoisting
The opening round. Almost every JavaScript interview starts here.
Basic
Q1
What is the difference between var, let and const?
var is function-scoped and hoisted as undefined, so it is readable before its declaration. let and const are block-scoped and sit in the temporal dead zone until their declaration line — reading them earlier throws. const additionally forbids reassignment of the binding.
The follow-upDoes const make an object immutable? No — the binding cannot be reassigned, but the object's properties can still be changed. Object.freeze() is the shallow fix.
Intermediate
Q2
What is a closure?
A function that keeps access to the variables of the scope it was created in, even after that scope has returned. The inner function holds a live reference to those variables, not a copy — which is what makes counters, private state and memoisation possible without a class.
function counter() {
let count = 0; // stays alive because increment closes over it
return function increment() { return ++count; };
}
const next = counter();
next(); // 1
next(); // 2
The follow-upThe classic trap: a var loop with a setTimeout inside logs the final value n times, because all iterations closed over one variable. let creates a fresh binding per iteration and fixes it.
Basic
Q3
What is hoisting?
Declarations are processed before any code runs. Function declarations are hoisted whole and callable before their definition; var declarations are hoisted and initialised to undefined; let and const are hoisted but left uninitialised, which is the temporal dead zone.
Basic
Q4
What is the difference between undefined and null?
undefined means a value was never assigned — the engine's default for a declared-but-unset variable, a missing argument, or a missing property. null is an explicit assignment meaning "deliberately empty". Practical rule: undefined happens to you, null is something you chose.
The follow-uptypeof null returns "object" — a bug from the first version of JavaScript that can never be fixed without breaking the web.
Basic
Q5
What is the difference between == and ===?
=== compares type and value with no conversion. == coerces first, which produces results nobody wants to memorise — '' == 0 and null == undefined are both true. Use === everywhere; the one defensible use of == is x == null to catch both null and undefined in one check.
Asynchronous JavaScript
The area interviewers probe hardest, because it is where bugs come from.
Intermediate
Q6
Explain the event loop.
JavaScript runs on one thread with a call stack. Async work is handed to the browser or Node, which calls back later by placing a task on a queue. The event loop moves a queued task onto the stack only when the stack is empty. That is why a long synchronous loop freezes the page — nothing queued can run until it finishes.
The follow-upThen: microtasks versus macrotasks. Promise callbacks go on the microtask queue, which is drained completely after each task — so a .then() always runs before a setTimeout(…, 0) queued at the same moment.
Advanced
Q7
What does this code log, and why?
Start, End, Promise, Timeout. The two synchronous logs run first. Then the microtask queue is drained, so the promise callback runs. The timeout is a macrotask and runs last, even with a delay of zero.
console.log('Start');
setTimeout(() => console.log('Timeout'), 0);
Promise.resolve().then(() => console.log('Promise'));
console.log('End');
Intermediate
Q8
What is a promise, and what are its states?
An object representing a value that is not available yet. It is pending until it either fulfils with a value or rejects with a reason, and once settled it never changes. Promises replaced nesting callbacks with chaining, so errors propagate down a chain to one .catch() instead of being handled at every level.
Intermediate
Q9
What is the difference between async/await and .then()?
None in behaviour — async/await is syntax over the same promises. The difference is readability: awaited code reads top to bottom, and try/catch works normally instead of a separate .catch(). Note that an async function always returns a promise, whatever you return inside it.
The follow-upA common performance mistake: awaiting inside a loop runs requests one after another. Build the promises first and await Promise.all(...) to run them together.
Advanced
Q10
What is the difference between Promise.all and Promise.allSettled?
Promise.all rejects as soon as any input rejects, and you lose the results of the ones that succeeded — right when every call must succeed. Promise.allSettled always fulfils with one entry per promise describing its outcome — right when you want whatever came back and will handle the failures individually.
Basic
Q11
What is a callback, and what is callback hell?
A function passed to another function to be called when work finishes. Callback hell is what happens when each step's result feeds the next: the code nests one level deeper each time, and errors must be handled separately at every level. Promises flatten the nesting; async/await removes it.
this, prototypes and objects
Where JavaScript stops resembling the languages candidates learned first.
Intermediate
Q12
How is the value of `this` determined?
By how the function is called, not where it is defined. Called as a method, this is the object before the dot. Called plainly, it is undefined in strict mode and the global object otherwise. Called with new, it is the new object. With call, apply or bind, it is whatever you passed. Arrow functions are the exception: they have no this of their own and take it from the enclosing scope.
The follow-upThat last point is why an arrow function is right for a callback inside a method and wrong as a method itself.
Advanced
Q13
What is prototypal inheritance?
Every object has a link to another object, its prototype. When a property is not found on an object, the lookup follows that link, and keeps following until it reaches null. Instead of copying members from a class into an instance, JavaScript delegates lookups along the chain — which is why adding a method to a prototype makes it available to every existing instance immediately.
The follow-upThen: are ES6 classes a different system? No — class is syntax over the same prototype mechanism, not a new inheritance model.
Intermediate
Q14
What is the difference between a shallow and a deep copy?
A shallow copy — the spread operator, Object.assign — duplicates the top level, so nested objects are still shared and mutating one is visible from the other. A deep copy duplicates everything. structuredClone() is the built-in that handles it correctly, including cycles.
Basic
Q15
What is the difference between map, filter, forEach and reduce?
map transforms each element and returns a new array of the same length. filter keeps the elements passing a test and returns a shorter array. forEach returns nothing and exists for side effects. reduce collapses the array to a single value — a sum, an object, a grouping.
The follow-upWhich do you use to sum an array? reduce. Using map and throwing away the result is a common tell.
Intermediate
Q16
What is event delegation?
Attaching one listener to a common ancestor instead of one per child, and using event.target to work out which child was clicked. It costs one listener rather than hundreds, and it automatically covers elements added to the DOM later — which is exactly what per-element listeners fail to do.
Advanced
Q17
What is the difference between debounce and throttle?
Debounce waits until the events stop, then fires once — right for a search box, where you want the request after typing pauses. Throttle fires at most once per interval while events continue — right for scroll or resize handlers, where you want steady updates but not one per pixel.
Modern JavaScript and the browser
Syntax you are expected to use, and the browser facts you are expected to know.
Basic
Q18
What does destructuring do, and where is it useful?
It pulls values out of an object or array into named variables in one statement, with defaults and renaming available. It is most useful in function parameters — a destructured object parameter documents what the function needs at the signature, and lets callers pass arguments in any order.
const { name, role = 'member', ...rest } = user;
const [first, second] = list;
function createUser({ name, email, admin = false }) { /* ... */ }
Intermediate
Q19
What is the difference between spread and rest?
Same three dots, opposite directions. Spread expands an iterable into individual elements — copying an array, merging objects, passing arguments. Rest collects the remaining items into one array or object — in a parameter list or on the left of a destructuring assignment.
Intermediate
Q20
What does optional chaining do, and what is the pitfall?
a?.b returns undefined instead of throwing when a is null or undefined. The pitfall is using it to paper over a value that should never be missing — it turns a loud failure into a silent undefined that surfaces somewhere far away. Pair it with ?? to supply a real fallback.
The follow-upThen: how does ?? differ from ||? || falls through on any falsy value, so 0 and '' get replaced. ?? only falls through on null and undefined.
Intermediate
Q21
What is the difference between a Map and a plain object?
A Map takes keys of any type, including objects; keeps insertion order guaranteed for all key types; exposes .size; and has no inherited keys to collide with. A plain object coerces keys to strings and carries prototype properties. Use a Map when the keys are dynamic or not strings, and an object when the shape is known.
Intermediate
Q22
What is the difference between localStorage, sessionStorage and cookies?
localStorage persists until cleared and is per origin. sessionStorage is the same API but cleared when the tab closes. Cookies are small, sent with every matching request — which is what makes them right for session tokens and wrong for anything large. For an auth token, an HttpOnly cookie is safer than localStorage, because script cannot read it.
Advanced
Q23
What is CORS, and why does it block your request?
The browser enforces the same-origin policy: script on one origin cannot read a response from another unless that server opts in with Access-Control-Allow-Origin. The block happens in the browser, and the fix is on the server — no amount of client-side code changes it. A non-simple request also triggers a preflight OPTIONS that the server must answer.
Advanced
Q24
What is the difference between an ES module and CommonJS?
ES modules use import/export, are statically analysable — which is what enables tree shaking — and are the standard in browsers. CommonJS uses require/module.exports, resolves at runtime so it can be called conditionally, and is Node's original system. Node supports both; the file extension or "type": "module" decides.
Intermediate
Q25
What is the difference between call, apply and bind?
All three set this. call invokes immediately with arguments listed individually; apply invokes immediately with arguments in an array; bind invokes nothing and returns a new function with this fixed — which is what you want when passing a method as a callback.
Intermediate
Q26
How would you deep-clone an object today?
structuredClone(value) — it is built in, handles nested structures, Dates, Maps, Sets and cyclic references. The old JSON.parse(JSON.stringify(x)) trick silently drops functions and undefined, turns Dates into strings, and throws on a cycle.