JavaScript Interview Questions for Freshers (2026) — with Answers

Updated August 2026

JavaScript interviews are unlike Java or C++ interviews in one specific way: panels rarely test syntax, because the syntax is easy. They test behaviour — what a piece of code prints and why. The language has a set of well-known rough edges around scope, type coercion, asynchrony and `this`, and almost every fresher question is really a question about one of them.

That makes JavaScript unusually predictable to prepare for. The list of things actually asked is short: the event loop, closures, how `this` is determined, hoisting and the differences between var, let and const, promises and async/await, equality and coercion, prototypes, and the array methods. Prepare those nine areas properly and you have covered most of what a fresher panel has time to ask.

One structural tip before the questions. The event loop is to JavaScript what the URL walkthrough is to computer networks — a single answer that demonstrates the whole model at once, and the one interviewers most often use to decide how deep to probe afterwards. Rehearse it out loud until it flows. Answer each question below in 30–60 seconds and finish with why the behaviour exists, not just what it is.

Frequently asked questions

Explain the event loop. How does JavaScript handle asynchronous code if it is single-threaded?

JavaScript has one call stack, so it runs one thing at a time. Asynchronous work is not done by the language but by the environment — the browser or Node — which handles timers, network requests and I/O separately. When such an operation finishes, its callback is placed in a queue. The event loop's job is simple: when the call stack is empty, take the next callback from the queue and push it onto the stack. Crucially there are two queues with different priorities — the microtask queue, used by promise callbacks, is fully drained before the macrotask queue, used by setTimeout and similar. That is why a resolved promise's .then runs before a setTimeout with a delay of zero. Rehearse this answer end to end; it is the highest-return question in the entire subject.

What is a closure, and where would you actually use one?

A closure is a function that keeps access to the variables of the scope it was defined in, even after that outer function has returned. The inner function holds a live reference to that scope rather than a copy. The practical uses are what interviewers want after the definition: data privacy, since variables in the closed-over scope cannot be reached from outside, which is how a counter or a module keeps private state; and function factories, where you build a specialised function by capturing a value. Closures are also what makes the classic loop question behave the way it does — every callback created inside a `var` loop shares one variable, while `let` creates a fresh binding each iteration.

var vs let vs const — what actually differs?

Three things: scope, redeclaration and hoisting behaviour. `var` is function-scoped, can be redeclared, and is hoisted and initialised to undefined, so reading it before the declaration gives undefined rather than an error. `let` and `const` are block-scoped, cannot be redeclared in the same scope, and although they are hoisted they sit in the temporal dead zone until the declaration executes, so reading them early throws a ReferenceError. `const` additionally prevents reassignment of the binding — but not mutation of the value, so a const object's properties can still be changed, which is the follow-up question you should expect. Use const by default, let when you must reassign, and var essentially never in new code.

What is hoisting?

During compilation, declarations are registered in their scope before any code runs, so they appear to be moved to the top. Function declarations are hoisted completely and can be called before they appear in the source. `var` declarations are hoisted and initialised to undefined, which is why using one early gives undefined instead of an error. `let` and `const` are hoisted but not initialised, leaving them in the temporal dead zone until the declaration is reached. Function expressions and arrow functions assigned to variables follow the rules of the variable, not of functions — which is exactly the distinction the question is testing.

How is the value of `this` determined?

By how a function is called, not where it is defined — with one exception. In a plain function call `this` is undefined in strict mode and the global object otherwise. In a method call, `this` is the object before the dot. With `new`, it is the newly created object. With call, apply or bind, it is whatever you passed explicitly. The exception is arrow functions, which have no `this` of their own and inherit it from the enclosing lexical scope, which is precisely why arrow functions are used for callbacks inside methods. The classic trap: extracting a method into a variable and calling it loses the receiver, because `this` follows the call site.

Arrow functions vs regular functions?

Beyond shorter syntax, the differences are behavioural. Arrow functions do not have their own `this` — they inherit it lexically, which makes them ideal as callbacks inside methods and wrong as object methods themselves. They have no `arguments` object. They cannot be used as constructors, so `new` throws. And they cannot be generators. The practical rule to state: use arrow functions for callbacks and short inline functions, and regular functions where you need a dynamic `this`, such as object methods or prototype methods.

== vs === — explain type coercion.

`===` compares value and type with no conversion. `==` converts operands to a common type first, following rules that are famously unintuitive: `0 == "0"` is true, `null == undefined` is true but `null == 0` is false, and `[] == false` is true. Use `===` always, with one accepted idiom — `x == null` as a concise check for null or undefined together. When asked why `==` exists at all, the honest answer is that it is a legacy of the language's original design, kept for backward compatibility; knowing when the coercion rules apply matters more than memorising every case.

null vs undefined?

`undefined` means a variable has been declared but no value assigned, or a function returned nothing, or a property does not exist — it is the language's absence. `null` is an explicit assignment meaning "no value", set deliberately by a programmer. Two details worth adding: `typeof undefined` is "undefined" while `typeof null` is "object", a long-standing bug kept for compatibility; and `null == undefined` is true while `null === undefined` is false. Use null when you intend to signal emptiness, and let undefined mean it was never set.

Explain promises, and how async/await relates to them.

A promise is an object representing a value that is not available yet, in one of three states — pending, fulfilled or rejected — and once settled it never changes. You consume it with .then for success, .catch for errors and .finally for cleanup, and it exists to replace deeply nested callbacks, the pattern known as callback hell. async/await is syntax over the same mechanism: an async function always returns a promise, and await pauses that function until the promise settles, letting asynchronous code read like sequential code. Error handling moves from .catch to try/catch. Worth mentioning: Promise.all runs several in parallel and rejects if any fails, while Promise.allSettled waits for all outcomes regardless.

What does setTimeout with a delay of 0 actually do?

It does not run the callback immediately. It schedules it as a macrotask, so it runs only after the current synchronous code has finished and after the microtask queue has been drained. That is why code logging before and after a setTimeout(fn, 0) prints both synchronous lines first, and why a resolved promise's .then still runs before it. The delay is a minimum wait, not a guarantee of timing. This is the standard follow-up to the event loop question and is best answered by predicting the output of a small snippet out loud.

Explain map, filter and reduce.

All three are higher-order array methods that return without mutating the original. `map` transforms each element and returns a new array of the same length. `filter` returns a new array containing only elements passing a test, so the length may shrink. `reduce` collapses an array into a single value by carrying an accumulator through each element — it is the general case of which map and filter are special cases, which is why it is the one candidates fumble. Be ready to write a reduce that sums numbers or groups objects by a key, since that is the usual practical follow-up.

Shallow copy vs deep copy — how do you copy an object correctly?

A shallow copy duplicates the top level only, so nested objects remain shared references and mutating them affects both copies. The spread operator and Object.assign both produce shallow copies. A deep copy duplicates every level. The modern answer is structuredClone, which handles nesting, dates, maps and sets; the older idiom is JSON.parse(JSON.stringify(obj)), which works for plain data but silently loses functions, undefined values and dates, and breaks on circular references. Naming that trade-off is what separates a memorised answer from an understood one.

What is the prototype chain?

Every JavaScript object has an internal link to another object, its prototype. When you access a property, the engine looks on the object itself, then follows that link up the chain until it finds the property or reaches null. This is how inheritance works in JavaScript — delegation to another object rather than copying from a class. ES6 `class` syntax is largely sugar over this mechanism rather than a different system underneath, which is the point the question is usually probing. Methods defined on a prototype are shared by all instances rather than duplicated per instance, which is the memory reason for putting them there.

Explain event bubbling, capturing and event delegation.

When an event fires on an element it travels in phases: capturing from the document down to the target, then bubbling from the target back up. Handlers run in the bubbling phase by default; passing true as the third argument to addEventListener registers for the capturing phase. Event delegation exploits bubbling — instead of attaching a handler to every child, you attach one to the parent and inspect event.target to see what was clicked. That means fewer listeners and, importantly, it works for elements added dynamically later. Mention event.stopPropagation to halt travel and event.preventDefault to cancel the default action, and that they do different things.

What are call, apply and bind?

All three set `this` explicitly. `call` invokes the function immediately with arguments listed individually; `apply` invokes it immediately with arguments as an array; `bind` does not invoke it at all but returns a new function with `this` permanently fixed, which is why it was the standard fix for losing context in callbacks before arrow functions. The mnemonic panels expect: call is comma, apply is array, bind is later. A bound function's `this` cannot be rebound afterwards, which is an occasional follow-up.

Which values are falsy in JavaScript?

There are exactly eight: false, 0, -0, 0n, "", null, undefined, and NaN. Everything else is truthy — including an empty array and an empty object, which is the trap in this question, because both are truthy despite feeling empty. That is why checking an array with a plain truthiness test is a bug and you must check its length. Also worth naming: the logical OR fallback treats 0 and empty string as missing, whereas the nullish coalescing operator only falls back on null and undefined, which is usually what you actually wanted.

localStorage vs sessionStorage vs cookies?

localStorage stores data with no expiry, persisting until explicitly cleared, and is scoped to the origin. sessionStorage is identical in interface but cleared when the tab closes and is not shared between tabs. Cookies are much smaller, can carry an expiry, and — the key difference — are sent to the server with every matching request, which is why they are used for authentication while the storage APIs are not. All three are readable by JavaScript on the page, so none is a safe place for sensitive data; a cookie marked HttpOnly is the exception, precisely because scripts cannot read it.

What are debounce and throttle, and when would you use each?

Both limit how often a function runs in response to frequent events. Debounce waits until activity stops, running the function only after a quiet period — right for a search box, where you want one request after typing pauses rather than one per keystroke. Throttle runs the function at most once per interval regardless of how many events arrive — right for scroll or resize handlers, where you want regular updates but not hundreds per second. The one-line distinction: debounce waits for silence, throttle enforces a rate.

What is the difference between synchronous and asynchronous code, and why does it matter in the browser?

Synchronous code runs line by line, each statement blocking the next. Asynchronous code starts an operation and continues, handling the result later via a callback, promise or await. It matters because the browser runs your JavaScript on the same thread that handles rendering and user input — so a long synchronous task freezes the page, blocking clicks and animation until it finishes. That is the real reason network requests, timers and file operations are asynchronous, and saying it in those terms shows you understand the constraint rather than the syntax.

Is JavaScript worth preparing for 2027-batch placements if I am targeting service companies?

Yes, and increasingly so. Service companies staff a large share of front-end and full-stack projects, JavaScript appears in web-development rounds regardless of the language you wrote your coding test in, and it is the default language for any project you build to demonstrate on your resume. That said, sequence it sensibly: for mass recruiters, aptitude, one strong language for DSA, SQL and core CS come first, and JavaScript adds most value once those are solid or if you are specifically targeting front-end, full-stack or product-company roles. If you built a web project, expect these questions whatever the role.

Don't just read JavaScript questions — get asked them

Phiny's AI interviews you on exactly these topics, follows up on weak answers, and tells you what a stronger answer looks like. Text interviews are free and unlimited.

Start a free AI mock interview

How to prepare

Where these questions get asked