JavaScript Interview Questions and Answers for Freshers
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.
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.
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.
JavaScript
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.
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.
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.
=== 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
6 questions
The area interviewers probe hardest, because it is where bugs come from.
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.
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.
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.
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.
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.
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
6 questions
Where JavaScript stops resembling the languages candidates learned first.
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.
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.
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.
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.
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.
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
9 questions
Syntax you are expected to use, and the browser facts you are expected to know.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Practise out loud
Reading answers is not the same as giving them
Most candidates know the material and still stumble when asked out loud. Take a JavaScript mock interview where the interviewer follows up on what you actually say.