JavaScript Interview Questions and Answers (2026)

Master your frontend or full-stack interview with these 50 essential JavaScript interview questions. Detailed answers, code snippets, common pitfalls, and senior/lead engineering concepts.

Why JavaScript Mastery is Key to Passing Technical Interviews

JavaScript remains the undisputed language of the web. Whether you are interviewing for a Frontend, Full Stack, or Node.js Backend engineering role at top tech companies like Google, Meta, Amazon, Microsoft, Uber, or Netflix, your core JavaScript knowledge will be tested.

Interviewers ask JavaScript questions not just to see if you know the syntax, but to evaluate your mental model of:

  1. The Runtime Environment: How the browser or Node.js processes asynchronous operations (Event Loop, Call Stack, Task Queues).
  2. Memory Management: How closures, references, and scopes impact application scalability and memory leaks.
  3. Code Optimization: Your ability to write high-performance code under pressure using patterns like debouncing, throttling, and virtualization.
  4. Problem Solving & Adaptability: How you approach language edge cases, prototype inheritance, and scope boundaries.

This comprehensive guide compiles the top 50 JavaScript interview questions, organized by category, ranging from junior fundamentals to advanced architectural concepts.

---

Section 1: Fundamentals (Variables, Scope, Hoisting, Data Types)

Q1: What is the difference between `var`, `let`, and `const`?

"Use const by default to enforce immutability of references, let when you expect a variable to change, and avoid var entirely to prevent accidental global leakage and scoping bugs due to hoisting."

Q2: What is Hoisting and the Temporal Dead Zone (TDZ)?

console.log(a); // undefined (var is hoisted and initialized)
// console.log(b); // ReferenceError (b is in TDZ)
var a = 1;
let b = 2;

Q3: What is the difference between `==` and `===`?

"Always use === to prevent bugs caused by implicit coercion. The only widely accepted exception is comparing to null/undefined via val == null to catch both."

Q4: Explain the primitive data types in JavaScript.

"JavaScript has seven primitive types. They are passed by value and immutable. Everything else is a reference type (objects, arrays, functions) stored on the heap."

Q5: What is a Symbol and how is it used?

const myPrivateField = Symbol('id');
const obj = { [myPrivateField]: 123 };
console.log(obj[myPrivateField]); // 123

Q6: What is a BigInt and why is it needed?

"Create a BigInt by appending n to an integer literal (e.g., 10n). It is essential for representing large database IDs or high-precision cryptographic values."

Q7: Explain Implicit Type Coercion.

"Implicit coercion occurs when operators encounter mismatched types. Use explicit conversions like Number() or String() to keep operations predictable."

Q8: What are falsy values in JavaScript?

"The values that evaluate to false in a boolean context include false, zero variants, empty strings, null, undefined, and NaN. Be careful with empty arrays or objects, as they evaluate to truthy."

---

Section 2: Functions & Closures (Closures, Scope Chains, Currying)

Q9: What is a Closure? Explain with a practical code example.

function createCounter() {
  let count = 0; // encapsulated state
  return {
    increment: () => ++count,
    decrement: () => --count,
    getCount: () => count
  };
}
const counter = createCounter();
console.log(counter.increment()); // 1

Q10: What is a Higher-Order Function (HOF)?

const numbers = [1, 2, 3];
const double = num => num * 2;
const doubled = numbers.map(double); // map is the HOF

Q11: Explain Function Currying and write a helper function to curry any function.

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    }
    return function(...nextArgs) {
      return curried.apply(this, args.concat(nextArgs));
    };
  };
}
const sum = (a, b, c) => a + b + c;
const curriedSum = curry(sum);
console.log(curriedSum(1)(2)(3)); // 6

Q12: What is the difference between Function Declarations and Function Expressions?

"Function declarations are fully hoisted and bind to the enclosing scope. Function expressions are treated as variable assignments and are only available after execution reaches their definition."

Q13: What is the difference between Call, Apply, and Bind?

const person = { name: 'Alice' };
function greet(greeting, punctuation) {
  console.log(`${greeting}, ${this.name}${punctuation}`);
}
greet.call(person, 'Hello', '!'); // call
greet.apply(person, ['Hi', '.']); // apply
const bound = greet.bind(person, 'Hey'); // bind
bound('?');

---

Section 3: Execution Model (Call Stack, Event Loop, Microtasks)

Q14: How does the JavaScript Event Loop work?

  1. JS runs in a single-threaded runtime. Execution context is pushed onto the Call Stack.
  2. Async operations (Web APIs like setTimeout, fetch) run in the background.
  3. Once finished, their callbacks are queued in the Task Queues.
  4. The Event Loop continually checks the Call Stack. If the stack is empty, it flushes the Microtask Queue completely before taking one task from the Macrotask Queue.
"The Event Loop coordinates code execution. It flushes the Call Stack, drains all microtasks (promises), allows the browser to re-render, and then executes the next macrotask (timers/I/O)."
   +-------------------------------------------------+
   |                  CALL STACK                     |
   +-----------------------+-------------------------+
                           |
                           | (Async web API finishes)
                           v
   +-----------------------+-------------------------+
   |             MICROTASK QUEUE (Promises)          |
   +-----------------------+-------------------------+
                           | (Flushed completely)
                           v
   +-----------------------+-------------------------+
   |            MACROTASK QUEUE (Timers, I/O)        |
   +-----------------------+-------------------------+
                           | (One executed per loop)
                           v
                       [Render]

Q15: What is the difference between Macrotasks and Microtasks? Provide execution order.

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

Q16: What is a Stack Overflow in JavaScript?

"Stack overflow occurs when too many execution contexts are pushed onto the Call Stack. To prevent it, always ensure your recursive functions have a verified base case or utilize loop iterations for heavy computations."

Q17: Explain the creation and execution phases of Execution Context.

"In the creation phase, the JS engine hoists functions and initialized variables. In the execution phase, it processes logic step-by-step. This separation explains TDZ and variable initialization behavior."

---

Section 4: Asynchronous JavaScript (Promises, Async/Await, Combinators)

Q18: What is a Promise? Explain its states.

  1. pending: Initial state, neither fulfilled nor rejected.
  2. fulfilled: Operation completed successfully.
  3. rejected: Operation failed.
"A Promise wraps async logic, starting as pending and resolving into either fulfilled or rejected. Once settled, its state cannot be modified."

Q19: Explain the difference between `Promise.all`, `Promise.allSettled`, `Promise.any`, and `Promise.race`.

// Use Promise.allSettled when you want to execute multiple independent requests 
// and analyze their individual results regardless of failure.
const results = await Promise.allSettled([p1, p2, p3]);

Q20: How does `async/await` handle errors under the hood?

async function fetchData() {
  try {
    const response = await fetch('/api');
    return await response.json();
  } catch (err) {
    console.error('Fetch failed:', err);
  }
}

Q21: What is a Promise Race condition? How can you cancel a Promise?

const controller = new AbortController();
fetch('/api', { signal: controller.signal })
  .catch(err => {
    if (err.name === 'AbortError') console.log('Cancelled!');
  });
controller.abort(); // Cancels the request

---

Section 5: Objects & Prototypes (Prototype Chain, `this` Binding)

Q22: What is Prototype Inheritance and the Prototype Chain?

const animal = { eats: true };
const rabbit = Object.create(animal); // sets animal as prototype
console.log(rabbit.eats); // true (inherited)
console.log(rabbit.__proto__ === animal); // true

Q23: How does the `this` keyword resolve inside a nested function?

const obj = {
  name: 'Alice',
  greet() {
    // Arrow function inherits 'this' from greet context
    const inner = () => console.log(this.name);
    inner();
  }
};
obj.greet(); // Alice

Q24: What is the difference between `__proto__` and `prototype`?

"An instance's __proto__ points to its creator's prototype. E.g., let arr = []; arr.__proto__ === Array.prototype is true."

Q25: Explain Object descriptors and how to freeze an object.

const obj = { nested: { a: 1 } };
Object.freeze(obj);
obj.nested.a = 2; // works! Freeze is shallow

---

Section 6: ES6+ (let/const, Arrow Functions, Spread/Rest)

Q26: Explain the difference in `this` binding between Arrow Functions and Regular Functions.

"Regular functions bind this at call-time. Arrow functions capture this lexically at creation-time, making them perfect for callbacks inside class methods or timers."

Q27: What is the difference between Spread (`...`) and Rest (`...`) operators?

"Spread unpacks items, while Rest packs them. Use Spread to clone arrays or merge objects, and Rest to collect dynamic arguments inside functions."

Q28: How does Destructuring work with alias mapping and default values?

const user = { name: 'Bob' };
const { name: userName, age = 25 } = user; // Alias and Default
console.log(userName, age); // Bob, 25

---

Section 7: Performance (Debouncing, Throttling, Memory Leaks)

Q29: Implement a Debounce function and explain its use case.

function debounce(fn, delay) {
  let timerId;
  return function(...args) {
    clearTimeout(timerId);
    timerId = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

Q30: Implement a Throttle function and explain its use case.

function throttle(fn, limit) {
  let inThrottle;
  return function(...args) {
    if (!inThrottle) {
      fn.apply(this, args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
}

Q31: What are the main causes of memory leaks in JavaScript?

  1. Accidental global variables (not using let/const).
  2. Uncleared interval timers or callbacks.
  3. Out-of-DOM references (holding DOM element nodes in memory).
  4. Uncleared event listeners on unmounted components (in SPAs).
"Memory leaks occur when references are no longer needed but are still retained in memory. Prevent them by clearing timers, unsubscribing from event listeners, and scoping variables strictly."

---

Section 8: Browser Concepts & DOM

Q32: What is the difference between Event Bubbling and Event Capturing?

"Events start in the capturing phase traveling downward, and transition to the bubbling phase rising upward. Add listener on capturing phase by setting the third parameter useCapture to true."

Q33: What is Event Delegation and why is it beneficial?

document.getElementById('parent-list').addEventListener('click', (e) => {
  if (e.target && e.target.nodeName === 'LI') {
    console.log('List item clicked:', e.target.innerText);
  }
});

Q34: What is the difference between `stopImmediatePropagation()` and `stopPropagation()`?

"Use stopPropagation to prevent bubbling to parent elements. Use stopImmediatePropagation if you want to abort other handlers on the same element from executing immediately."

---

Section 9: Advanced Concepts (Map vs Set, WeakMap, Generators)

Q35: What is the difference between `Map` and `Object`?

"Use Map when you need dynamic key-value pairs with non-string keys or require frequent insertion/deletion, as it performs better at scale."

Q36: What is a `WeakMap` and when would you use it?

"Use WeakMap for caching data or storing metadata for objects without blocking garbage collection (e.g., storing private metadata about DOM nodes)."

Q37: How do Generator functions work?

function* idGenerator() {
  let id = 1;
  while (true) yield id++;
}
const gen = idGenerator();
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2

Q38: Explain the difference between Shallow Copy and Deep Copy.

"Use shallow copy for flat objects. For nested objects, use the modern native structuredClone() to deep copy without losing standard data types."

Q39: What is Currying vs Partial Application?

"Currying converts a function of arity N into N functions of arity 1. Partial application binds a subset of parameters, returning a function of smaller arity."

Q40: What is a Pure Function and what are side effects?

"Pure functions make code predictable and testable. They do not read or modify external state and do not cause side effects."

---

Section 10: OOP & Classes

Q41: How do JavaScript ES6 Classes differ from Constructor Functions?

"Classes provide cleaner syntax but are prototypal. They enforce strict mode, prevent invocation without new, and make method inheritance clean."

Q42: What is the `super` keyword in JavaScript?

class Animal { constructor(name) { this.name = name; } }
class Dog extends Animal {
  constructor(name, breed) {
    super(name); // parent call
    this.breed = breed;
  }
}

Q43: How do you declare private fields in modern JS classes?

class BankAccount {
  #balance = 0; // Private field
  deposit(amount) { this.#balance += amount; }
}

Q44: What is the difference between Static Methods and Instance Methods?

"Static methods are defined with the static keyword and exist on the class itself, not on instances. Use them for helper functions."

---

Section 11: Google & Meta Style JavaScript Questions

Q45: Implement a custom Promise class from scratch.

class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.handlers = [];
    const resolve = (val) => {
      if (this.state !== 'pending') return;
      this.state = 'fulfilled';
      this.value = val;
      this.handlers.forEach(h => queueMicrotask(h));
    };
    executor(resolve);
  }
  then(callback) {
    return new MyPromise((res) => {
      const handler = () => res(callback(this.value));
      if (this.state === 'fulfilled') queueMicrotask(handler);
      else this.handlers.push(handler);
    });
  }
}

Q46: Implement a deep comparison function (`deepEqual(a, b)`).

function deepEqual(a, b) {
  if (a === b) return true;
  if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) return false;
  const keysA = Object.keys(a);
  const keysB = Object.keys(b);
  if (keysA.length !== keysB.length) return false;
  for (let key of keysA) {
    if (!keysB.includes(key) || !deepEqual(a[key], b[key])) return false;
  }
  return true;
}

Q47: Implement a Memoize helper function.

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.apply(this, args);
    cache.set(key, result);
    return result;
  };
}

Q48: Flatten a nested array recursively (without using `Array.prototype.flat()`).

function flatten(arr) {
  return arr.reduce((acc, val) => 
    Array.isArray(val) ? acc.concat(flatten(val)) : acc.concat(val), []
  );
}

Q49: Explain the difference between microtask throttling and standard throttling.

"Use requestAnimationFrame instead of setTimeout for UI-bound throttling, as it triggers changes synchronized with the screen's refresh rate."

Q50: How do you check if a value is an Array?

"Always use Array.isArray() to check values, as it is the most reliable built-in helper across environment contexts."

---

Senior JavaScript Interview Questions

  1. Explain the V8 engine compilation pipeline: Discuss Ignition interpreter, TurboFan compiler, hot functions, and de-optimization behaviors.
  2. How would you implement a custom Garbage Collection detection mechanism? Discuss using FinalizationRegistry to track object cleanup.
  3. Explain the difference between Service Workers, Web Workers, and Worklets: Web Workers run scripts in background threads; Service Workers intercept network requests; Worklets are hook points into browser rendering pipeline.
  4. Implement custom module federation resolver: How micro-frontends share JavaScript bundles dynamically.

---

Google & Meta Style Practice Questions

  1. Distributed event emitter: Build an event emitter that coordinates events across multiple browser windows using BroadcastChannel.
  2. Trie-based autocomplete: Implement a client-side search indexing engine that operates with O(K) lookup constraints.
  3. Visual viewport virtualization: Build an infinite scroll system that virtualizes elements to keep memory footprints constant.

---

Quick Revision Notes

---

5 Practical Interview Tips

  1. Vocalize constraints: Always discuss complexity (Time & Space) before writing code.
  2. Draw first: Explain the event loop execution flows or prototype inheritance chains visually.
  3. Narrate your logic: Avoid long silent coding blocks. Tell the interviewer what you are writing.
  4. Review your code: Trace values manually with simple parameters before declaring your code complete.
  5. Admit limits: If you do not know a native implementation, discuss the mental logic of the approach.

---

Frequently Asked Questions (FAQs)

#### Q: How does JavaScript execute asynchronous code if it is single-threaded?

A: The JS engine itself is single-threaded (Call Stack), but the surrounding environment (Browser/Node) provides multithreaded APIs (timers, network, file operations). When async tasks complete, their callbacks are queued and executed on the JS main thread via the Event Loop.

#### Q: What is the main cause of memory leaks with closures?

A: Storing functions inside active objects that retain references to large parameters in their lexical environment, preventing the garbage collector from reclaiming that memory.

#### Q: Can const variables change value?

A: For primitive values (like numbers or strings), no. For reference values (objects, arrays), yes. You cannot reassign the variable name to point to a new value, but you can mutate the object's properties or push values to the array.

#### Q: What is the difference between Object.create and new?

A: Object.create(proto) directly creates a new object with the specified prototype. new Constructor() executes the constructor function, sets this to point to a new instance whose prototype is bound, and returns the instance.

---

Ready to Test Your JavaScript Skills?

Mastering the theory is only half the battle. To pass your technical rounds at top product companies, you need to perform under pressure.

Try InterviewMantra's AI-Powered Mock Interviews

[👉 Try a Free AI Mock Interview Now](https://interviewmantra.in/register)

Frequently Asked Questions

How does JavaScript execute asynchronous code if it is single-threaded?

The JS engine itself is single-threaded (Call Stack), but the surrounding environment (Browser/Node) provides multithreaded APIs (timers, network, file operations). When async tasks complete, their callbacks are queued and executed on the JS main thread via the Event Loop.

What is the main cause of memory leaks with closures?

Storing functions inside active objects that retain references to large parameters in their lexical environment, preventing the garbage collector from reclaiming that memory.

Can const variables change value?

For primitive values (like numbers or strings), no. For reference values (objects, arrays), yes. You cannot reassign the variable name to point to a new value, but you can mutate the object's properties or push values to the array.

What is the difference between Object.create and new?

Object.create(proto) directly creates a new object with the specified prototype. new Constructor() executes the constructor function, sets this to point to a new instance whose prototype is bound, and returns the instance.