Interview Prep

Top 50 JavaScript
Interview Questions

Master the most frequently asked JavaScript questions in tech interviews — with clear, concise answers you can actually remember.

50 Questions Beginner to Advanced Regularly Updated Used in Real Interviews

No questions match your search. Try a different keyword.

Basics

Core JavaScript Basics

1 What are the key features of JavaScript?

JavaScript is a lightweight, interpreted, high-level programming language with these key features:

  • Dynamic typing — variable types are determined at runtime.
  • First-class functions — functions can be passed as arguments, returned from other functions, and assigned to variables.
  • Prototype-based OOP — objects inherit directly from other objects via prototypes.
  • Event-driven & asynchronous — supports callbacks, promises, and async/await for non-blocking code.
  • Single-threaded — runs on one thread using an event loop to handle concurrency.
  • Runs everywhere — browser (client-side) and server (Node.js).
2 What is the difference between var, let, and const?
  • var — function-scoped, hoisted to the top of its function (initialized as undefined), can be re-declared and reassigned.
  • let — block-scoped, hoisted but NOT initialized (temporal dead zone), cannot be re-declared in the same scope, can be reassigned.
  • const — block-scoped, hoisted but NOT initialized, cannot be re-declared or reassigned. Objects/arrays declared with const can still be mutated.
var x = 1;  let y = 2;  const z = 3;
{
  var x = 10;  // same variable — overwrites outer x
  let y = 20;  // new block-scoped variable
}
console.log(x); // 10   (var leaks out)
console.log(y); // 2    (let stays block-scoped)
3 What is hoisting in JavaScript?

Hoisting is JavaScript's behavior of moving variable and function declarations to the top of their scope before code executes — but only the declaration, not the initialization.

console.log(a); // undefined (not ReferenceError)
var a = 5;

greet(); // works — function declarations are fully hoisted
function greet() { console.log("Hello"); }

console.log(b); // ReferenceError — let/const are hoisted
let b = 10;    // but stay in the temporal dead zone
4 What is the difference between == and ===?

== is the loose equality operator — it performs type coercion before comparing. === is the strict equality operator — it compares both value and type without coercion.

0 == false    // true  (false coerced to 0)
0 === false   // false (different types)
"5" == 5      // true  (string coerced to number)
"5" === 5     // false

Always prefer === to avoid unexpected bugs from type coercion.

5 What is the difference between null and undefined?
  • undefined — a variable has been declared but not yet assigned a value. JS assigns it automatically.
  • null — an intentional absence of any value. The developer explicitly sets it to signal "no value here".
let a;           // undefined — declared, not assigned
let b = null;    // null — intentionally empty

typeof undefined // "undefined"
typeof null      // "object" (legacy JS quirk)

null == undefined  // true  (loose equality)
null === undefined // false (strict equality)
6 What are JavaScript data types?

JavaScript has 8 data types:

Primitive (7): string, number, bigint, boolean, undefined, null, symbol

Non-primitive (1): object — includes plain objects, arrays, functions, dates, maps, sets, etc.

Primitives are immutable and stored by value. Objects are stored by reference.

7 What is the DOM?

The Document Object Model (DOM) is a programming interface that represents an HTML/XML document as a tree of objects. JavaScript can use the DOM API to read and manipulate page content, structure, and styles.

// Select an element
const btn = document.getElementById('myBtn');
// Modify content
btn.textContent = 'Click me';
// Add an event listener
btn.addEventListener('click', () => alert('Clicked!'));

The DOM is provided by the browser — it is not part of the JavaScript language spec itself.

Functions & Scope

Functions, Scope & Closures

8 Explain closures with an example.

A closure is a function that retains access to its outer (enclosing) scope even after the outer function has returned. The inner function "closes over" the outer variables.

function makeCounter() {
  let count = 0;          // outer variable
  return function () {    // inner function — closure
    count++;
    return count;
  };
}

const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2  — count persists!

Common uses: data encapsulation, factory functions, memoization, event handlers that remember state.

9 What are arrow functions and how do they differ from regular functions?

Arrow functions are a concise ES6 syntax for writing functions. Key differences:

  • No own this — arrow functions inherit this from their enclosing scope (lexical this). Regular functions get their own this depending on how they're called.
  • Cannot be used as constructors — no new keyword.
  • No arguments object — use rest parameters instead.
  • Cannot be generator functions.
// Regular function
const obj = {
  name: 'CB',
  greet: function() { console.log(this.name); } // 'CB'
};

// Arrow function — this refers to outer scope
const obj2 = {
  name: 'CB',
  greet: () => console.log(this.name) // undefined
};
10 What is the use of the this keyword in JavaScript?

this refers to the object that is currently executing the function. Its value depends on how the function is called:

  • Global contextthis is the global object (window in browser, global in Node).
  • Object methodthis is the object before the dot.
  • Constructor (new)this is the newly created object.
  • Arrow function — inherits this from the surrounding lexical scope.
  • call / apply / bind — explicitly set this.
11 What is the difference between call, apply, and bind?

All three explicitly set this for a function:

  • 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, …) — returns a new function with this bound permanently. Does NOT call it immediately.
function greet(greeting) {
  return `${greeting}, ${this.name}`;
}
const person = { name: 'Arjun' };
greet.call(person, 'Hello');    // "Hello, Arjun"
greet.apply(person, ['Hi']);    // "Hi, Arjun"
const bound = greet.bind(person, 'Hey');
bound();                         // "Hey, Arjun"
12 What are callback functions?

A callback is a function passed as an argument to another function, to be executed later — usually after an async operation or event completes.

function fetchData(callback) {
  setTimeout(() => {
    callback('data received');
  }, 1000);
}

fetchData(function(result) {
  console.log(result); // "data received" after 1s
});

Overusing callbacks leads to "callback hell" — deeply nested, hard-to-read code. Promises and async/await solve this.

13 What is scope and what are the different types in JavaScript?

Scope determines where a variable is accessible in your code. JavaScript has three scopes:

  • Global scope — variables declared outside any function or block; accessible everywhere.
  • Function scope — variables declared inside a function; accessible only within that function.
  • Block scope — variables declared with let/const inside { }; accessible only within that block.

JavaScript also follows the scope chain — when a variable isn't found locally, JS looks up the chain to the enclosing scope.

Async

Async JavaScript & Promises

14 What is a Promise in JavaScript?

A Promise is an object representing the eventual completion or failure of an asynchronous operation. It has three states: pending, fulfilled, and rejected.

const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Done!'), 1000);
});

promise
  .then(result => console.log(result))  // "Done!"
  .catch(err => console.error(err))
  .finally(() => console.log('Always runs'));

Promises solve callback hell by enabling chaining with .then() and .catch().

15 Explain async / await.

async/await is syntactic sugar over Promises that makes async code look and behave like synchronous code.

  • async — marks a function as asynchronous; it always returns a Promise.
  • await — pauses execution inside the async function until the Promise settles.
async function fetchUser() {
  try {
    const res = await fetch('https://api.example.com/user');
    const data = await res.json();
    console.log(data);
  } catch (err) {
    console.error('Error:', err);
  }
}

await can only be used inside an async function (or at the top level of ES modules).

16 What is the JavaScript Event Loop?

JavaScript is single-threaded. The event loop is the mechanism that allows JS to perform non-blocking operations by offloading work to the browser/Node APIs and processing callbacks when the call stack is empty.

  • Call Stack — executes synchronous code (LIFO).
  • Web APIs — browser handles async tasks (setTimeout, fetch, DOM events).
  • Callback/Task Queue — completed async callbacks wait here.
  • Microtask Queue — Promise callbacks run here, BEFORE the task queue.
  • Event Loop — continuously checks: is the stack empty? If yes, push next microtask/task onto the stack.
console.log('A');              // 1st
setTimeout(() => console.log('B'), 0); // 3rd (task queue)
Promise.resolve().then(() => console.log('C')); // 2nd (microtask)
console.log('D');              // 2nd sync
// Output: A, D, C, B
17 What is Promise.all() vs Promise.allSettled() vs Promise.race()?
  • Promise.all(arr) — runs all promises in parallel; resolves when ALL resolve, rejects immediately if ANY rejects.
  • Promise.allSettled(arr) — runs all promises; resolves when ALL settle (fulfilled or rejected), never short-circuits. Returns an array of status objects.
  • Promise.race(arr) — resolves/rejects as soon as the FIRST promise settles.
  • Promise.any(arr) — resolves as soon as the FIRST promise fulfills; rejects only if ALL reject.
18 What is the difference between setTimeout and setInterval?
  • setTimeout(fn, delay) — executes fn once after delay milliseconds.
  • setInterval(fn, delay) — executes fn repeatedly every delay milliseconds until clearInterval() is called.
const id = setInterval(() => console.log('tick'), 1000);
setTimeout(() => clearInterval(id), 5000); // stop after 5s

Note: the actual delay may be slightly longer than specified due to the event loop and minimum timer resolution (4ms in browsers).

OOP

OOP & Prototypes

19 What is a prototype in JavaScript?

Every JavaScript object has a hidden internal link called [[Prototype]] (accessible via __proto__ or Object.getPrototypeOf()). This points to another object called its prototype. When you access a property that doesn't exist on an object, JS looks up the prototype chain until it finds it or reaches null.

const arr = [1, 2, 3];
// arr doesn't have 'map' itself — it finds it on Array.prototype
arr.map(x => x * 2); // [2, 4, 6]
20 What is prototypal inheritance?

JavaScript objects inherit properties and methods directly from other objects through the prototype chain — this is prototypal inheritance.

const animal = { breathes: true };
const dog = Object.create(animal);
dog.bark = function() { return 'Woof!'; };

console.log(dog.breathes); // true — inherited from animal
console.log(dog.bark());   // 'Woof!' — own property

ES6 class syntax is syntactic sugar over this prototype-based system.

21 How do ES6 classes work in JavaScript?

ES6 classes are syntactic sugar over constructor functions and prototype-based inheritance. They make OOP more readable but don't change the underlying prototype mechanism.

class Animal {
  constructor(name) { this.name = name; }
  speak() { return `${this.name} makes a sound.`; }
}

class Dog extends Animal {
  speak() { return `${this.name} barks.`; }
}

const d = new Dog('Rex');
d.speak(); // "Rex barks."
d instanceof Animal; // true
22 What is the difference between Object.create() and the new keyword?
  • Object.create(proto) — creates a new object with proto as its prototype. No constructor function is called. Useful for pure prototypal inheritance.
  • new Constructor() — creates a new object, sets its prototype to Constructor.prototype, runs the constructor function with this bound to the new object, and returns it.
DOM

DOM & Events

23 What is event bubbling and event capturing?

When an event fires on an element, it propagates through the DOM in two phases:

  • Capturing (trickling down) — the event travels from the root down to the target element. Handlers registered with { capture: true } fire here.
  • Bubbling (default) — after reaching the target, the event bubbles back up to the root. Default addEventListener handlers fire here.
// Stop propagation to prevent bubbling further
element.addEventListener('click', (e) => {
  e.stopPropagation();
});
24 What is event delegation?

Event delegation means attaching a single event listener to a parent element instead of each child — leveraging event bubbling. This is efficient for dynamic lists or many similar elements.

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

Benefits: fewer listeners (better memory), works for dynamically added elements.

25 What is the difference between e.preventDefault() and e.stopPropagation()?
  • e.preventDefault() — cancels the default browser action for an event (e.g., stops a form from submitting, stops a link from navigating). The event still propagates.
  • e.stopPropagation() — prevents the event from bubbling/capturing further up or down the DOM. The default action still happens.
26 What is the difference between innerHTML, innerText, and textContent?
  • innerHTML — gets/sets the HTML markup inside an element (parses HTML tags). Risk: XSS if used with user input.
  • innerText — gets/sets the human-readable rendered text only (respects CSS visibility, triggers reflow).
  • textContent — gets/sets all text including hidden elements; faster than innerText, does not parse HTML.
Advanced

Advanced Concepts

27 What is the difference between shallow copy and deep copy?
  • Shallow copy — copies an object one level deep. Nested objects are still referenced (not duplicated). Spread { ...obj } and Object.assign() are shallow.
  • Deep copy — recursively copies all levels. Changes to the copy do not affect the original.
// Shallow
const a = { x: 1, nested: { y: 2 } };
const b = { ...a };
b.nested.y = 99;
console.log(a.nested.y); // 99 — mutated original!

// Deep copy (simple objects, no functions/dates)
const c = JSON.parse(JSON.stringify(a));
// Or use structuredClone() in modern JS
const d = structuredClone(a);
28 What is memoization?

Memoization is an optimization technique that caches the results of expensive function calls so that when the same inputs occur again, the cached result is returned instead of recomputing.

function memoize(fn) {
  const cache = new Map();
  return function(...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) return cache.get(key);
    const result = fn(...args);
    cache.set(key, result);
    return result;
  };
}

const factorial = memoize(n => n <= 1 ? 1 : n * factorial(n - 1));
factorial(10); // computed
factorial(10); // returned from cache
29 What is currying?

Currying transforms a function with multiple arguments into a sequence of functions each taking one argument.

// Normal
const add = (a, b) => a + b;
add(2, 3); // 5

// Curried
const curriedAdd = a => b => a + b;
const add5 = curriedAdd(5);
add5(3); // 8   (partial application)
add5(7); // 12

Useful for creating reusable, partially-applied functions and in functional programming.

30 What are generators in JavaScript?

Generator functions (declared with function*) return an iterator. They can pause execution with yield and resume later, making them useful for lazy evaluation, async flow control, and infinite sequences.

function* counter() {
  let i = 0;
  while (true) {
    yield i++;
  }
}

const gen = counter();
gen.next().value; // 0
gen.next().value; // 1
gen.next().value; // 2  (infinite, no overflow)
31 What are WeakMap and WeakSet?
  • WeakMap — a Map where keys must be objects. Entries are weakly held — if the key object is garbage-collected, the entry disappears automatically. Not iterable, no .size.
  • WeakSet — a Set of objects only, weakly held. Useful for tracking objects without preventing their garbage collection.

Use them to store metadata about objects (e.g., DOM nodes) without memory leaks.

32 What is a Symbol in JavaScript?

Symbol is a primitive type introduced in ES6. Every Symbol() call returns a unique, immutable value — even if given the same description. Symbols are often used as unique object property keys that won't clash with other keys or be accidentally iterated.

const id1 = Symbol('id');
const id2 = Symbol('id');
id1 === id2; // false — always unique

const obj = {};
obj[id1] = 123;
// id1 won't appear in for...in or Object.keys()
33 What is the Temporal Dead Zone (TDZ)?

The Temporal Dead Zone is the period between the start of a block scope and the point where a let or const variable is declared. During the TDZ, any attempt to access the variable throws a ReferenceError.

console.log(x); // ReferenceError — in TDZ
let x = 5;
console.log(x); // 5  — after declaration
34 What is the difference between for...of and for...in?
  • for...in — iterates over enumerable property keys of an object (including inherited ones). Best used for plain objects.
  • for...of — iterates over values of any iterable (arrays, strings, Maps, Sets, generators). Does not work on plain objects.
const arr = [10, 20, 30];
for (const i in arr) console.log(i); // "0", "1", "2" (keys)
for (const v of arr) console.log(v); // 10, 20, 30 (values)
35 What are destructuring and the spread/rest operators?

Destructuring — extract values from arrays/objects into variables.

const [a, b] = [1, 2];                     // array
const { name, age = 25 } = { name: 'Arjun' }; // object with default

Spread (...) — expands an iterable into individual elements.

const merged = [...arr1, ...arr2];
const copy = { ...original, newKey: 1 };

Rest (...) — collects remaining elements into an array.

function sum(...nums) { return nums.reduce((a, b) => a + b, 0); }
sum(1, 2, 3, 4); // 10
36 What is type coercion in JavaScript?

Type coercion is the automatic conversion of a value from one type to another by JavaScript's engine.

  • Implicit coercion — happens automatically: 1 + "2""12" (number to string).
  • Explicit coercion — done intentionally: Number("5"), String(42), Boolean(0).
"5" - 2   // 3   (string coerced to number)
"5" + 2   // "52" (number coerced to string)
!!"hello" // true (truthy coercion)
37 What are Proxy and Reflect in JavaScript?

Proxy wraps an object and intercepts operations on it (get, set, delete, etc.) via traps. Used for validation, logging, reactive systems (Vue 3 uses it).

const handler = {
  set(target, key, value) {
    if (typeof value !== 'number') throw new Error('Numbers only!');
    target[key] = value;
    return true;
  }
};
const safe = new Proxy({}, handler);
safe.score = 95;   // ok
safe.score = 'A';  // Error!

Reflect provides static methods that mirror Proxy traps, making it easy to perform default operations inside traps.

38 What is a Higher-Order Function (HOF)?

A Higher-Order Function is a function that either takes one or more functions as arguments, returns a function, or both. They are a pillar of functional programming in JS.

// Takes a function as argument
[1, 2, 3].map(x => x * 2);   // [2, 4, 6]
[1, 2, 3].filter(x => x > 1); // [2, 3]
[1, 2, 3].reduce((acc, x) => acc + x, 0); // 6

// Returns a function
const multiply = factor => num => num * factor;
const double = multiply(2);
double(5); // 10
39 What is IIFE (Immediately Invoked Function Expression)?

An IIFE is a function that is defined and immediately executed. It creates its own scope, preventing variable leakage into the global scope.

(function () {
  const secret = 42;
  console.log('Runs immediately!');
})();

// Arrow IIFE
(() => console.log('Also an IIFE'))();

Common before ES6 modules for encapsulation. Less common now with block scoping and modules.

40 What is the difference between Map and a plain object?
  • Key typesMap accepts any value (objects, functions, primitives) as keys; plain objects only accept strings/symbols.
  • OrderMap preserves insertion order; plain object order is mostly insertion-order for strings but not guaranteed for integer keys.
  • SizeMap has a .size property; plain objects need Object.keys(obj).length.
  • IterationMap is directly iterable with for...of.
  • PerformanceMap is faster for frequent add/remove operations.
41 What is Object.freeze() vs Object.seal()?
  • Object.freeze(obj) — prevents adding, removing, or modifying any properties. The object becomes completely immutable (shallow).
  • Object.seal(obj) — prevents adding or removing properties, but existing properties can still be modified (if writable).
const obj = Object.freeze({ x: 1 });
obj.x = 99; // silently fails (throws in strict mode)
obj.x;      // still 1

const obj2 = Object.seal({ y: 1 });
obj2.y = 99; // works — modification allowed
obj2.z = 3;  // silently fails — no new properties
42 What is debouncing and throttling?
  • Debouncing — delays function execution until after a specified wait time has elapsed since the last call. Useful for search input fields (fire only when the user stops typing).
  • Throttling — ensures a function fires at most once every N milliseconds. Useful for scroll/resize events.
// Debounce
function debounce(fn, delay) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

// Throttle
function throttle(fn, limit) {
  let last = 0;
  return function(...args) {
    const now = Date.now();
    if (now - last >= limit) { last = now; fn(...args); }
  };
}
43 What is the difference between synchronous and asynchronous code?
  • Synchronous — code executes line by line, each line blocking the next until it completes. Simple but can freeze the UI for long operations.
  • Asynchronous — code initiates an operation and moves on; a callback/promise handles the result when ready. Allows other code to run while waiting for I/O, timers, or network requests.
// Sync — blocks
const data = fs.readFileSync('file.txt'); // waits here

// Async — non-blocking
fs.readFile('file.txt', (err, data) => {
  console.log(data); // runs later
});
console.log('This runs immediately');
44 What is localStorage vs sessionStorage vs cookies?
  • localStorage — stores data with no expiry. Persists across browser sessions. ~5–10 MB. Only accessible by the same origin. Not sent to server.
  • sessionStorage — stores data for the duration of the browser session (cleared when tab closes). Same-origin, not sent to server.
  • Cookies — small (~4 KB) key-value pairs with an optional expiry. Sent automatically with every HTTP request to the server. Can be HttpOnly (inaccessible to JS) and Secure.
45 What is optional chaining (?.) and nullish coalescing (??)?

Optional chaining ?. — safely accesses nested properties. If any part of the chain is null or undefined, the expression short-circuits and returns undefined instead of throwing.

const city = user?.address?.city; // undefined if address is null

Nullish coalescing ?? — returns the right-hand side only if the left-hand side is null or undefined (not falsy like 0 or "").

const name = user.name ?? 'Anonymous'; // 'Anonymous' only if null/undefined
const count = 0 ?? 10;   // 0  (0 is not null/undefined)
const count2 = 0 || 10;  // 10 (0 is falsy — || catches all falsy)
46 What are ES6 modules (import / export)?

ES6 modules allow splitting code into reusable files. Each module has its own scope.

// math.js — named exports
export const PI = 3.14;
export function add(a, b) { return a + b; }

// utils.js — default export
export default function log(msg) { console.log(msg); }

// main.js — importing
import { PI, add } from './math.js';
import log from './utils.js';         // default import (any name)

Modules are always in strict mode and load asynchronously. They differ from CommonJS (require/module.exports) used in Node.

47 What is strict mode in JavaScript?

Adding "use strict"; at the top of a file or function enables strict mode, which opts into a restricted variant of JS that:

  • Throws errors for silent mistakes (assigning to undeclared variables, duplicate parameter names).
  • Disallows with statements.
  • Makes this undefined (not global) in non-method functions.
  • Reserves future keywords (implements, interface, etc.).

ES6 modules and classes are always in strict mode automatically.

48 What is the difference between Array.map(), filter(), and reduce()?
  • map(fn) — transforms each element; returns a new array of the same length.
  • filter(fn) — keeps only elements where fn returns truthy; returns a new array (may be shorter).
  • reduce(fn, init) — reduces all elements to a single value (sum, object, nested array, etc.).
const nums = [1, 2, 3, 4, 5];
nums.map(x => x * 2);          // [2, 4, 6, 8, 10]
nums.filter(x => x % 2 === 0); // [2, 4]
nums.reduce((acc, x) => acc + x, 0); // 15
49 What is JSON and how do you use it in JavaScript?

JSON (JavaScript Object Notation) is a lightweight, text-based data-interchange format. It is a subset of JavaScript object literal syntax but supports only strings, numbers, booleans, null, objects, and arrays — no functions or undefined.

// JS object → JSON string
const json = JSON.stringify({ name: 'Arjun', age: 22 });
// '{"name":"Arjun","age":22}'

// JSON string → JS object
const obj = JSON.parse('{"name":"Arjun","age":22}');
obj.name; // 'Arjun'
50 What is the difference between throw and reject in error handling?
  • throw — raises an exception synchronously. Use it in synchronous code or inside async functions (where it gets converted into a rejected Promise).
  • reject() — rejects a Promise; used inside the Promise constructor to signal async failure.
// Synchronous
function divide(a, b) {
  if (b === 0) throw new Error('Division by zero');
  return a / b;
}

// Async — both are equivalent
async function fetchData() {
  throw new Error('Network error'); // same as reject
}

new Promise((_, reject) => {
  reject(new Error('Network error'));
});

In async functions, always use throw. In Promise constructors, use reject().

Ready to crack your next interview?

Join CodeBegun's Java Full Stack program — 145 days of real-world projects, mock interviews, and 1-on-1 mentorship with industry engineers.

Apply Now — Next Batch 1 June