JavaScript Interview Questions 2025

Introduction

JavaScript is one of the most popular programming languages in the world, powering more than 95% of websites. From front-end development (React, Angular, Vue) to back-end (Node.js), JavaScript is everywhere.

That’s why if you are preparing for a JavaScript developer interview, you’ll face a variety of questions ranging from basic concepts to tricky advanced scenarios.

In this blog, we’ll cover 100+ JavaScript interview questions with detailed answers and code examples. By the end, you’ll be well-prepared for your next front-end, back-end, or full-stack developer interview

Javascript interview questions

1. What is JavaScript?

JavaScript is a programming language that helps make websites interactive and dynamic. It was created in 1995 by Brendan Eich and is now maintained by ECMA International. JavaScript is lightweight and easy to use, making it a popular choice for web developers who want to build engaging and responsive websites.

2. What are the features of JavaScript?

Key features include:

  • Dynamic typing (no need to declare data types)

  • Object-oriented (prototype-based inheritance)

  • First-class functions (functions can be passed as arguments)

  • Asynchronous programming support (Promises, async/await)

  • Event-driven (commonly used in browsers)

  • Cross-platform (works on browsers, servers, mobile apps, etc.)

4. What are JavaScript data types?

JavaScript has two categories of data types:

  1. Primitive Types (Immutable)

    • String

    • Number

    • Boolean

    • Null

    • Undefined

    • BigInt

    • Symbol

  2. Non-Primitive (Reference) Types

    • Object

    • Array

    • Function

    • Date
    • Regular Expressions (RegExp)
📄
filename.js
let name = "Rohit"; // String
let age = 23;       // Number
let isDev = true;   // Boolean
let user = { id: 1, role: "admin" }; // Object
let arr = ['a','b','c','d']  // Array

5. What is the difference between null and undefined?

  • undefined → A variable that has been declared but not assigned a value.

  • null → An assigned value representing “no value” or “empty object”.

📄
filename.js
let a;
console.log(a); // undefined

let b = null;
console.log(b); // null

6. What is the difference between == and === in JavaScript?

  • == → Loose equality, checks only values (perform type coercion than compare).

  • === → Strict equality, checks values and types both.

📄
filename.js
console.log(5 == "5");  // true  
console.log(5 === "5"); // false

Here’s the simple breakdown:

  • == is the loose equality operator.

  • Before comparing the two values, JavaScript automatically tries to convert them to a common type.

  • In this case, it converts the string "5" into the number 5.

  • So, it effectively compares 5 == 5, which is obviously true.

If you want to check if the values are the same and of the same type, you use the strict equality operator (===).

  • console.log(5 === "5") // false

  • This is false because a number (5) is not the same type as a string ("5").

7. What is Hoisting ?

Hoisting is a javascript behaviour where function and variable declaration moved to top of their respective scope during the compilation phase.

📄
Hoisting.js
console.log(message); //output : undefined
var message = "The variable Has been hoisted";

The above code looks like as below to the interpreter,

📄
Hoisting.js
var message;
console.log(message);
message = "The variable Has been hoisted";

In the same fashion, function declarations are hoisted too

📄
Hoisting.js
message("Good morning"); //Good morning

function message(name) {
  console.log(name);
}

This hoisting makes functions to be safely used in code before they are declared.

9. What is the difference between var, let, and const?

Feature Var Let Const
Scope
Function-scoped
Block-scoped
Block-scoped
Hoisting
Yes (initialized as undefined)
Yes (TDZ)
Yes (TDZ)
Re-declaration
Allowed
Not allowed
Not allowed
Re-assignment
Allowed
Allowed
Not allowed

10. What is the Temporal Dead Zone (TDZ)?

In simple terms, the Temporal Dead Zone (TDZ) is the period between when a variable is declared (using let or const) and when it is fully initialized (i.e., when it gets its value). You cannot access the variable at all during this period. Trying to do so will result in a ReferenceError.

This behavior is part of JavaScript’s ES6 (ECMAScript 2015) specification and applies only to variables declared with let and const, not var. Variables declared with var are hoisted and initialized with undefined, so accessing them before the declaration does not throw an error, though it can lead to unexpected results.

📄
TDZ.js
function someMethod() {
    console.log(counter1); // Output: undefined (due to var hoisting)
    console.log(counter2); // Throws ReferenceError (TDZ for let)

    var counter1 = 1;
    let counter2 = 2;
}

11. What are higher-order functions?

A Higher-Order Function is a function that takes one or more functions as arguments or returns a function as its output.

📄
HOF.js
function greet(name) {
  return `Hello, ${name}`;
}

function higherOrder(fn, value) {
  return fn(value);
}

console.log(higherOrder(greet, "Rohit")); // Hello, Rohit

Example: The .map() method
The .map() function is a higher-order function because it takes a function as its argument to tell it what to do to each item in the array.

📄
HOFExample.js
const numbers = [1, 2, 3, 4];

// The function `num => num * 2` is the argument to the higher-order function `.map()`
const doubled = numbers.map(num => num * 2);

console.log(doubled); // [2, 4, 6, 8]

Other common examples: filter()forEach()reduce()setTimeout()addEventListener().

📄
HOFExample.js
// addEventListener is a HOF that takes a function (the click handler)
button.addEventListener('click', function() {
  console.log('Button was clicked!');
});

12. What is a callback function?

A Callback function is a function that is passed as an argument to the another function.

📄
Callback.js
function callbackFunction(name) {
  console.log("Hello " + name);
}

function outerFunction(callback) {
  let name = prompt("Please enter your name.");
  callback(name);
}

outerFunction(callbackFunction);

13. What are Promises in JavaScript?

Promise is a JavaScript object that represents the eventual completion (or failure) of an asynchronous operation and its resulting value. It acts as a placeholder for a value that may not be available yet but will be resolved in the future.

A Promise can be in one of three states:

  • pending: Initial state, neither fulfilled nor rejected.
  • fulfilled: The operation completed successfully.
  • rejected: The operation failed (e.g., due to a network error).

Example: Creating and Using a Promise

📄
Promise.js
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("I'm a Promise!");
  }, 5000);
});

promise
  .then((value) => console.log(value)); // Logs after 5 seconds: "I'm a Promise!"
  .catch((error) => console.error(error))  // Handles any rejection
  .finally(() => console.log("Done"));     // Runs regardless of success or failure

In the above example:

  • Promise is created to handle an asynchronous operation with resolve and reject callbacks.
  • The setTimeout resolves the promise with a value after 5 seconds.
  • .then().catch(), and .finally() are used to handle success, errors, and cleanup respectively.

The action flow of a promise will be as below,

Promise flow

14. Why do you need a promise

Promises are used to handle asynchronous operations, especially in languages like JavaScript, which often work with non-blocking operations such as network requests, file I/O, and timers. When an operation is asynchronous, it doesn’t immediately return a result; instead, it works in the background and provides the result later. Handling this in a clean, organized way can be difficult without a structured approach.

Promises are used to:

  1. Handle asynchronous operations.
  2. Provide a cleaner alternative to callbacks.
  3. Avoid callback hell.
  4. Make code more readable and maintainable.

15. Why do we need callbacks

We need callbacks for one primary reason: to manage asynchronous operations in a single-threaded environment like JavaScript without freezing the entire program.

The Core Problem: JavaScript is Single-Threaded

Imagine JavaScript has only one worker (one thread). This worker can only do one task at a time. If it had to stop and wait for every slow task (like downloading a file, waiting for a timer, or querying a database), your entire webpage or application would freeze completely. This would be a terrible user experience.

The Solution: Non-Blocking Asynchronous Operations

Callbacks are the original solution to this problem. The idea is:

  1. “Hey, Worker, go start this slow task. But don’t just stand there and wait for it!.”

  2. “Here’s a ‘callback’ function—a set of instructions. Go work on something else, and when that slow task finishes, come back and execute this callback.”

This is called a non-blocking model. The main thread isn’t blocked; it’s free to handle other things, like user clicks or animations, while waiting.

The Evolution: From Callbacks to Promises and Async/Await

While callbacks are essential, deeply nested callbacks lead to “Callback Hell” (pyramid-shaped, hard-to-read code).

Modern JavaScript evolved better patterns to manage asynchronous flow:

  • Promises: Provide a cleaner, chainable syntax (.then().catch()) to handle async operations and errors.

  • Async/Await: Makes asynchronous code look and behave like synchronous code, which is much easier to read and write.

16. What is a callback hell

Callback Hell (also known as the “Pyramid of Doom”) is a pattern of writing asynchronous JavaScript code with multiple nested callbacks. This nesting makes the code extremely difficult to read, debug, and maintain.

It happens when you have one asynchronous operation that depends on the result of the previous asynchronous operation, which in turn depends on the result of the one before it, and so on.

Imagine you need to do a series of tasks that depend on each other:

  1. Get a user’s profile.

  2. Then, get their list of friends from that profile.

  3. Then, get the latest post from one of those friends.

With nested callbacks, it looks like this:

📄
CallbackHell.js
getUserProfile(userId, function(user) {
  getFriendList(user, function(friends) {
    getLatestPost(friends[0], function(post) {
      console.log('The latest post is:', post);
      // And it could keep nesting deeper... 
    });
  });
});

See the problem? The code:

  • Grows horizontally to the right instead of vertically downward, forming a pyramid.

  • Becomes hard to follow and reason about.

  • Is very brittle and difficult to error-handle (you’d need to check for errors at every single level).

This structure is “Callback Hell.”

17. Difference between synchronous and asynchronous JavaScript?

  • Synchronous → Code runs line by line, blocking execution.

  • Asynchronous → Non-blocking, uses callbacks, promises, async/await.

📄
asynchronous.js
console.log("Start");

setTimeout(() => console.log("Async Task"), 1000);

console.log("End");

// Output: Start → End → Async Task

18. What is an Event Delegation?

Event delegation is a technique in JavaScript where you attach an event listener to a parent element instead of individual child elements. This single parent listener can then handle events that bubble up from any of its children, all thanks to Event Bubbling.

19. What is Event Bubbling?

Event Bubbling is a type of event propagation in the DOM. When an event occurs on an element, it doesn’t just stop at that element. Instead, the event “bubbles up” through the DOM tree, triggering event listeners on parent elements until it reaches the root element (usually the document object).

Event bubbling allows you to use event delegation, where you attach an event listener to a parent element to handle events on its child elements.
Example:
🌐
bubbling.html
<div id="grandparent">
  <div id="parent">
    <button id="child">Click me</button>
  </div>
</div>
📄
bubbling.js
document.getElementById('grandparent').addEventListener('click', () => {
  console.log('Grandparent clicked');
});

document.getElementById('parent').addEventListener('click', () => {
  console.log('Parent clicked');
});

document.getElementById('child').addEventListener('click', () => {
  console.log('Child clicked');
});

// When you click the button, you will see the following output

// Child clicked
// Parent clicked
// Grandparent clicked

20. What is event capturing?

Event capturing is the opposite of event bubbling. When an event occurs, it starts from the root element (usually the document object) and “trickles down” to the target element. This process is called event capturing.

📄
capturing.js
document.getElementById('grandparent').addEventListener('click', () => {
  console.log('Grandparent capturing');
}, true);

document.getElementById('parent').addEventListener('click', () => {
  console.log('Parent bubbling');
});

document.getElementById('child').addEventListener('click', () => {
  console.log('Child bubbling');
});

document.getElementById('parent').addEventListener('click', () => {
  console.log('Parent capturing');
}, true);

// Output

// Grandparent capturing
// Parent capturing
// Child bubbling
// Parent bubbling

21. What is the use of stopPropagation method

  • The stopPropagation method is used to prevent further propagation of an event in the capturing and bubbling phases. When you call stopPropagation on an event, it stops the event from bubbling up to parent elements or trickling down to child elements.
    Here’s what stopPropagation does:
    • Prevents event bubbling: Stops the event from propagating to parent elements.
    • Prevents event capturing: Stops the event from propagating to child elements in the capturing phase.
    Example:
🌐
StopPropagation.html
<div id="grandparent">
  <div id="parent">
    <button id="child">Click me</button>
  </div>
</div>
📄
StopPropagation.js
document.getElementById('grandparent').addEventListener('click', () => {
  console.log('Grandparent clicked');
});

document.getElementById('parent').addEventListener('click', () => {
  console.log('Parent clicked');
});

document.getElementById('child').addEventListener('click', (event) => {
  console.log('Child clicked');
  event.stopPropagation();
});

// Output
// Child clicked

22. What is the use of setTimeout()

In simple terms, setTimeout is a function that schedules a piece of code to run once after a specified minimum delay. It’s a core tool for handling timing and asynchronous operations in JavaScript.

It tells the JavaScript engine: “Wait this long, then execute this function.”

📄
SetTimeOut.js
console.log('Before timeout');
setTimeout(() => {
  console.log('After 2 seconds');
}, 2000);
console.log('After setTimeout call');

// Output
// Before timeout
// After setTimeout call
// After 2 seconds

23. What is the use of clearTimeout()

setTimeout returns a timeout ID, which can be used to cancel the timeout using clearTimeout.

📄
clearTimeout.js
const timeoutId = setTimeout(() => {
  console.log('Timeout');
}, 1000);
clearTimeout(timeoutId); // Cancel the timeout

24. What is the use of setInterval() and clearInterval()

setInterval is a JavaScript function that allows you to execute a function repeatedly at a specified interval. The interval is specified in milliseconds.

📄
setInterval.js
let count = 0;
const intervalId = setInterval(() => {
  console.log(`Interval ${count}`);
  count++;
  if (count >= 5) {
    clearInterval(intervalId);
  }
}, 1000);

setInterval returns an interval ID, which can be used to cancel the interval using clearInterval.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top